Compare commits

...

3 Commits

Author SHA1 Message Date
Engel Nyst
feab5024d0 Clean out debug print (#7666) 2025-04-02 14:17:25 -04:00
Robert Brennan
ab0ab6fc6a dont return asterisks for api key (#7654)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-04-02 12:46:22 -04:00
mamoodi
0a4307a0de Release 0.31.0 2025-04-02 08:45:26 -04:00
40 changed files with 86 additions and 82 deletions

View File

@@ -118,7 +118,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/all-hands-ai/runtime:0.30-nikolaik`
Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.31-nikolaik`
## Develop inside Docker container

View File

@@ -43,17 +43,17 @@ See the [Running OpenHands](https://docs.all-hands.dev/modules/usage/installatio
system requirements and more information.
```bash
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/.openhands-state:/.openhands-state \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.30
docker.all-hands.dev/all-hands-ai/openhands:0.31
```
> [!WARNING]

View File

@@ -11,7 +11,7 @@ services:
- BACKEND_HOST=${BACKEND_HOST:-"0.0.0.0"}
- SANDBOX_API_HOSTNAME=host.docker.internal
#
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.30-nikolaik}
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.31-nikolaik}
- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234}
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
ports:

View File

@@ -7,7 +7,7 @@ services:
image: openhands:latest
container_name: openhands-app-${DATE:-}
environment:
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik}
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-docker.all-hands.dev/all-hands-ai/runtime:0.31-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-state for this user
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
ports:

View File

@@ -52,7 +52,7 @@ LLM_API_KEY="sk_test_12345"
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -61,7 +61,7 @@ docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.30 \
docker.all-hands.dev/all-hands-ai/openhands:0.31 \
python -m openhands.core.cli
```

View File

@@ -46,7 +46,7 @@ LLM_API_KEY="sk_test_12345"
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -56,6 +56,6 @@ docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.30 \
docker.all-hands.dev/all-hands-ai/openhands:0.31 \
python -m openhands.core.main -t "write a bash script that prints hi" --no-auto-continue
```

View File

@@ -13,16 +13,16 @@
La façon la plus simple d'exécuter OpenHands est avec Docker.
```bash
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.30
docker.all-hands.dev/all-hands-ai/openhands:0.31
```
Vous pouvez également exécuter OpenHands en mode [headless scriptable](https://docs.all-hands.dev/modules/usage/how-to/headless-mode), en tant que [CLI interactive](https://docs.all-hands.dev/modules/usage/how-to/cli-mode), ou en utilisant l'[Action GitHub OpenHands](https://docs.all-hands.dev/modules/usage/how-to/github-action).

View File

@@ -13,7 +13,7 @@ C'est le Runtime par défaut qui est utilisé lorsque vous démarrez OpenHands.
```
docker run # ...
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-v /var/run/docker.sock:/var/run/docker.sock \
# ...
```

View File

@@ -34,7 +34,7 @@ Docker で OpenHands を CLI モードで実行するには:
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -44,7 +44,7 @@ docker run -it \
-v ~/.openhands-state:/.openhands-state \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.30 \
docker.all-hands.dev/all-hands-ai/openhands:0.31 \
python -m openhands.core.cli
```

View File

@@ -31,7 +31,7 @@ DockerでOpenHandsをヘッドレスモードで実行するには:
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -42,7 +42,7 @@ docker run -it \
-v ~/.openhands-state:/.openhands-state \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.30 \
docker.all-hands.dev/all-hands-ai/openhands:0.31 \
python -m openhands.core.main -t "write a bash script that prints hi"
```

View File

@@ -25,7 +25,7 @@ nikolaik の `SANDBOX_RUNTIME_CONTAINER_IMAGE` は、ランタイムサーバー
```bash
docker run # ...
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-v $WORKSPACE_BASE:/opt/workspace_base \
@@ -82,5 +82,5 @@ docker network create openhands-network
# 分離されたネットワークで OpenHands を実行
docker run # ... \
--network openhands-network \
docker.all-hands.dev/all-hands-ai/openhands:0.30
docker.all-hands.dev/all-hands-ai/openhands:0.31
```

View File

@@ -35,7 +35,7 @@ Para executar o OpenHands no modo CLI com Docker:
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -45,7 +45,7 @@ docker run -it \
-v ~/.openhands-state:/.openhands-state \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.30 \
docker.all-hands.dev/all-hands-ai/openhands:0.31 \
python -m openhands.core.cli
```

View File

@@ -32,7 +32,7 @@ Para executar o OpenHands no modo Headless com Docker:
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -43,7 +43,7 @@ docker run -it \
-v ~/.openhands-state:/.openhands-state \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.30 \
docker.all-hands.dev/all-hands-ai/openhands:0.31 \
python -m openhands.core.main -t "escreva um script bash que imprima oi"
```

View File

@@ -58,17 +58,17 @@
A maneira mais fácil de executar o OpenHands é no Docker.
```bash
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/.openhands-state:/.openhands-state \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.30
docker.all-hands.dev/all-hands-ai/openhands:0.31
```
Você encontrará o OpenHands em execução em http://localhost:3000!

View File

@@ -13,7 +13,7 @@ Este é o Runtime padrão que é usado quando você inicia o OpenHands. Você po
```
docker run # ...
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-v /var/run/docker.sock:/var/run/docker.sock \
# ...
```

View File

@@ -50,7 +50,7 @@ LLM_API_KEY="sk_test_12345"
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -59,7 +59,7 @@ docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.30 \
docker.all-hands.dev/all-hands-ai/openhands:0.31 \
python -m openhands.core.cli
```

View File

@@ -47,7 +47,7 @@ LLM_API_KEY="sk_test_12345"
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -57,6 +57,6 @@ docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.30 \
docker.all-hands.dev/all-hands-ai/openhands:0.31 \
python -m openhands.core.main -t "write a bash script that prints hi" --no-auto-continue
```

View File

@@ -11,16 +11,16 @@
在 Docker 中运行 OpenHands 是最简单的方式。
```bash
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.30
docker.all-hands.dev/all-hands-ai/openhands:0.31
```
你也可以在可脚本化的[无头模式](https://docs.all-hands.dev/modules/usage/how-to/headless-mode)下运行 OpenHands作为[交互式 CLI](https://docs.all-hands.dev/modules/usage/how-to/cli-mode),或使用 [OpenHands GitHub Action](https://docs.all-hands.dev/modules/usage/how-to/github-action)。

View File

@@ -11,7 +11,7 @@
```
docker run # ...
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-v /var/run/docker.sock:/var/run/docker.sock \
# ...
```

View File

@@ -35,7 +35,7 @@ To run OpenHands in CLI mode with Docker:
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -45,7 +45,7 @@ docker run -it \
-v ~/.openhands-state:/.openhands-state \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.30 \
docker.all-hands.dev/all-hands-ai/openhands:0.31 \
python -m openhands.core.cli
```

View File

@@ -32,7 +32,7 @@ To run OpenHands in Headless mode with Docker:
```bash
docker run -it \
--pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e SANDBOX_USER_ID=$(id -u) \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-e LLM_API_KEY=$LLM_API_KEY \
@@ -43,7 +43,7 @@ docker run -it \
-v ~/.openhands-state:/.openhands-state \
--add-host host.docker.internal:host-gateway \
--name openhands-app-$(date +%Y%m%d%H%M%S) \
docker.all-hands.dev/all-hands-ai/openhands:0.30 \
docker.all-hands.dev/all-hands-ai/openhands:0.31 \
python -m openhands.core.main -t "write a bash script that prints hi"
```

View File

@@ -58,17 +58,17 @@ A system with a modern processor and a minimum of **4GB RAM** is recommended to
The easiest way to run OpenHands is in Docker.
```bash
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.30-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.31-nikolaik \
-e LOG_ALL_EVENTS=true \
-v /var/run/docker.sock:/var/run/docker.sock \
-v ~/.openhands-state:/.openhands-state \
-p 3000:3000 \
--add-host host.docker.internal:host-gateway \
--name openhands-app \
docker.all-hands.dev/all-hands-ai/openhands:0.30
docker.all-hands.dev/all-hands-ai/openhands:0.31
```
You'll find OpenHands running at http://localhost:3000!

View File

@@ -18,7 +18,7 @@ describe("useSaveSettings", () => {
),
});
result.current.mutate({ LLM_API_KEY: "" });
result.current.mutate({ llm_api_key: "" });
await waitFor(() => {
expect(saveSettingsSpy).toHaveBeenCalledWith(
expect.objectContaining({
@@ -27,7 +27,7 @@ describe("useSaveSettings", () => {
);
});
result.current.mutate({ LLM_API_KEY: null });
result.current.mutate({ llm_api_key: null });
await waitFor(() => {
expect(saveSettingsSpy).toHaveBeenCalledWith(
expect.objectContaining({

View File

@@ -395,7 +395,7 @@ describe("Settings Screen", () => {
it("should render an indicator if the LLM API key is set", async () => {
getSettingsSpy.mockResolvedValueOnce({
...MOCK_DEFAULT_USER_SETTINGS,
llm_api_key: "**********",
llm_api_key_set: true,
});
renderSettingsScreen();
@@ -416,7 +416,7 @@ describe("Settings Screen", () => {
it("should set '<hidden>' placeholder if the LLM API key is set", async () => {
getSettingsSpy.mockResolvedValueOnce({
...MOCK_DEFAULT_USER_SETTINGS,
llm_api_key: "**********",
llm_api_key_set: true,
});
renderSettingsScreen();
@@ -971,7 +971,7 @@ describe("Settings Screen", () => {
const user = userEvent.setup();
getSettingsSpy.mockResolvedValue({
...MOCK_DEFAULT_USER_SETTINGS,
llm_api_key: "**********",
llm_api_key_set: true,
});
renderSettingsScreen();

View File

@@ -1,12 +1,12 @@
{
"name": "openhands-frontend",
"version": "0.30.1",
"version": "0.31.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openhands-frontend",
"version": "0.30.1",
"version": "0.31.0",
"dependencies": {
"@heroui/react": "2.7.5",
"@monaco-editor/react": "^4.7.0-rc.0",

View File

@@ -1,6 +1,6 @@
{
"name": "openhands-frontend",
"version": "0.30.1",
"version": "0.31.0",
"private": true,
"type": "module",
"engines": {

View File

@@ -50,7 +50,7 @@ export function SettingsForm({ settings, models, onClose }: SettingsFormProps) {
posthog.capture("settings_saved", {
LLM_MODEL: newSettings.LLM_MODEL,
LLM_API_KEY: newSettings.LLM_API_KEY ? "SET" : "UNSET",
LLM_API_KEY_SET: newSettings.LLM_API_KEY_SET ? "SET" : "UNSET",
REMOTE_RUNTIME_RESOURCE_FACTOR:
newSettings.REMOTE_RUNTIME_RESOURCE_FACTOR,
});
@@ -74,7 +74,7 @@ export function SettingsForm({ settings, models, onClose }: SettingsFormProps) {
}
};
const isLLMKeySet = settings.LLM_API_KEY === "**********";
const isLLMKeySet = settings.LLM_API_KEY_SET;
return (
<div>

View File

@@ -21,9 +21,9 @@ const saveSettingsMutationFn = async (
confirmation_mode: settings.CONFIRMATION_MODE,
security_analyzer: settings.SECURITY_ANALYZER,
llm_api_key:
settings.LLM_API_KEY === ""
settings.llm_api_key === ""
? ""
: settings.LLM_API_KEY?.trim() || undefined,
: settings.llm_api_key?.trim() || undefined,
remote_runtime_resource_factor: settings.REMOTE_RUNTIME_RESOURCE_FACTOR,
enable_default_condenser: settings.ENABLE_DEFAULT_CONDENSER,
enable_sound_notifications: settings.ENABLE_SOUND_NOTIFICATIONS,

View File

@@ -15,7 +15,7 @@ const getSettingsQueryFn = async () => {
LANGUAGE: apiSettings.language,
CONFIRMATION_MODE: apiSettings.confirmation_mode,
SECURITY_ANALYZER: apiSettings.security_analyzer,
LLM_API_KEY: apiSettings.llm_api_key,
LLM_API_KEY_SET: apiSettings.llm_api_key_set,
REMOTE_RUNTIME_RESOURCE_FACTOR: apiSettings.remote_runtime_resource_factor,
PROVIDER_TOKENS_SET: apiSettings.provider_tokens_set,
ENABLE_DEFAULT_CONDENSER: apiSettings.enable_default_condenser,
@@ -45,10 +45,10 @@ export const useSettings = () => {
});
React.useEffect(() => {
if (query.isFetched && query.data?.LLM_API_KEY) {
if (query.isFetched && query.data?.LLM_API_KEY_SET) {
posthog.capture("user_activated");
}
}, [query.data?.LLM_API_KEY, query.isFetched]);
}, [query.data?.LLM_API_KEY_SET, query.isFetched]);
React.useEffect(() => {
if (query.data?.PROVIDER_TOKENS_SET) {

View File

@@ -12,7 +12,8 @@ import { GitUser } from "#/types/git";
export const MOCK_DEFAULT_USER_SETTINGS: ApiSettings | PostApiSettings = {
llm_model: DEFAULT_SETTINGS.LLM_MODEL,
llm_base_url: DEFAULT_SETTINGS.LLM_BASE_URL,
llm_api_key: DEFAULT_SETTINGS.LLM_API_KEY,
llm_api_key: null,
llm_api_key_set: DEFAULT_SETTINGS.LLM_API_KEY_SET,
agent: DEFAULT_SETTINGS.AGENT,
language: DEFAULT_SETTINGS.LANGUAGE,
confirmation_mode: DEFAULT_SETTINGS.CONFIRMATION_MODE,

View File

@@ -77,7 +77,7 @@ function AccountSettings() {
providerTokensSet.includes(ProviderOptions.github) || false;
const isGitLabTokenSet =
providerTokensSet.includes(ProviderOptions.gitlab) || false;
const isLLMKeySet = settings?.LLM_API_KEY === "**********";
const isLLMKeySet = settings?.LLM_API_KEY_SET;
const isAnalyticsEnabled = settings?.USER_CONSENTS_TO_ANALYTICS;
const isAdvancedSettingsSet = determineWhetherToToggleAdvancedSettings();
@@ -120,11 +120,11 @@ function AccountSettings() {
const enableSoundNotifications =
formData.get("enable-sound-notifications-switch")?.toString() === "on";
const llmBaseUrl = formData.get("base-url-input")?.toString() || "";
const inputApiKey = formData.get("llm-api-key-input")?.toString() || "";
const llmApiKey =
formData.get("llm-api-key-input")?.toString() ||
(isLLMKeySet
? undefined // don't update if it's already set
: ""); // reset if it's first time save to avoid 500 error
inputApiKey === "" && isLLMKeySet
? undefined // don't update if it's already set and input is empty
: inputApiKey; // otherwise use the input value
const githubToken = formData.get("github-token-input")?.toString();
const gitlabToken = formData.get("gitlab-token-input")?.toString();
@@ -151,7 +151,7 @@ function AccountSettings() {
ENABLE_SOUND_NOTIFICATIONS: enableSoundNotifications,
LLM_MODEL: finalLlmModel,
LLM_BASE_URL: finalLlmBaseUrl,
LLM_API_KEY: finalLlmApiKey,
llm_api_key: finalLlmApiKey,
AGENT: formData.get("agent-input")?.toString(),
SECURITY_ANALYZER:
formData.get("security-analyzer-input")?.toString() || "",
@@ -277,10 +277,10 @@ function AccountSettings() {
label="API Key"
type="password"
className="w-[680px]"
placeholder={isLLMKeySet ? "<hidden>" : ""}
startContent={
isLLMKeySet && <KeyStatusIcon isSet={isLLMKeySet} />
}
placeholder={isLLMKeySet ? "<hidden>" : ""}
/>
)}

View File

@@ -7,7 +7,7 @@ export const DEFAULT_SETTINGS: Settings = {
LLM_BASE_URL: "",
AGENT: "CodeActAgent",
LANGUAGE: "en",
LLM_API_KEY: null,
LLM_API_KEY_SET: false,
CONFIRMATION_MODE: false,
SECURITY_ANALYZER: "",
REMOTE_RUNTIME_RESOURCE_FACTOR: 1,

View File

@@ -2,14 +2,14 @@ enum ArgConfigType {
LLM_MODEL = "LLM_MODEL",
AGENT = "AGENT",
LANGUAGE = "LANGUAGE",
LLM_API_KEY = "LLM_API_KEY",
LLM_API_KEY_SET = "LLM_API_KEY_SET",
}
const SupportedSettings: string[] = [
ArgConfigType.LLM_MODEL,
ArgConfigType.AGENT,
ArgConfigType.LANGUAGE,
ArgConfigType.LLM_API_KEY,
ArgConfigType.LLM_API_KEY_SET,
];
export { ArgConfigType, SupportedSettings };

View File

@@ -17,7 +17,7 @@ export interface InitConfig {
AGENT: string;
CONFIRMATION_MODE: boolean;
LANGUAGE: string;
LLM_API_KEY: string;
LLM_API_KEY_SET: boolean;
LLM_MODEL: string;
};
token?: string;

View File

@@ -10,7 +10,7 @@ export type Settings = {
LLM_BASE_URL: string;
AGENT: string;
LANGUAGE: string;
LLM_API_KEY: string | null;
LLM_API_KEY_SET: boolean;
CONFIRMATION_MODE: boolean;
SECURITY_ANALYZER: string;
REMOTE_RUNTIME_RESOURCE_FACTOR: number | null;
@@ -28,6 +28,7 @@ export type ApiSettings = {
agent: string;
language: string;
llm_api_key: string | null;
llm_api_key_set: boolean;
confirmation_mode: boolean;
security_analyzer: string;
remote_runtime_resource_factor: number | null;
@@ -41,6 +42,7 @@ export type ApiSettings = {
export type PostSettings = Settings & {
provider_tokens: Record<Provider, string>;
user_consents_to_analytics: boolean | null;
llm_api_key?: string | null;
};
export type PostApiSettings = ApiSettings & {

View File

@@ -47,7 +47,9 @@ const extractAdvancedFormData = (formData: FormData) => {
};
};
export const extractSettings = (formData: FormData): Partial<Settings> => {
export const extractSettings = (
formData: FormData,
): Partial<Settings> & { llm_api_key?: string | null } => {
const { LLM_MODEL, LLM_API_KEY, AGENT, LANGUAGE } =
extractBasicFormData(formData);
@@ -73,7 +75,7 @@ export const extractSettings = (formData: FormData): Partial<Settings> => {
return {
LLM_MODEL: CUSTOM_LLM_MODEL || LLM_MODEL,
LLM_API_KEY,
LLM_API_KEY_SET: !!LLM_API_KEY,
AGENT,
LANGUAGE,
LLM_BASE_URL,
@@ -81,5 +83,6 @@ export const extractSettings = (formData: FormData): Partial<Settings> => {
SECURITY_ANALYZER,
ENABLE_DEFAULT_CONDENSER,
PROVIDER_TOKENS: providerTokens,
llm_api_key: LLM_API_KEY,
};
};

View File

@@ -328,7 +328,7 @@ def main() -> None:
runtime_container_image = my_args.runtime_container_image
if runtime_container_image is None:
runtime_container_image = 'ghcr.io/all-hands-ai/runtime:0.30.0-nikolaik'
runtime_container_image = 'ghcr.io/all-hands-ai/runtime:0.31.0-nikolaik'
owner, repo = my_args.selected_repo.split('/')
token = my_args.token or os.getenv('GITHUB_TOKEN') or os.getenv('GITLAB_TOKEN')

View File

@@ -10,7 +10,6 @@ from openhands.server.settings import GETSettingsModel, POSTSettingsModel, Setti
from openhands.server.shared import SettingsStoreImpl, config, server_config
from openhands.server.types import AppMode
app = APIRouter(prefix='/api')
@@ -27,10 +26,10 @@ async def load_settings(request: Request) -> GETSettingsModel | JSONResponse:
)
provider_tokens_set = {}
if bool(user_id):
provider_tokens_set[ProviderType.GITHUB.value] = True
provider_tokens = get_provider_tokens(request)
if provider_tokens:
all_provider_types = [provider.value for provider in ProviderType]
@@ -43,10 +42,10 @@ async def load_settings(request: Request) -> GETSettingsModel | JSONResponse:
settings_with_token_data = GETSettingsModel(
**settings.model_dump(exclude='secrets_store'),
llm_api_key_set=settings.llm_api_key is not None,
provider_tokens_set=provider_tokens_set,
)
settings_with_token_data.llm_api_key = settings.llm_api_key
settings_with_token_data.llm_api_key = None
return settings_with_token_data
except Exception as e:
logger.warning(f'Invalid token: {e}')

View File

@@ -121,3 +121,4 @@ class GETSettingsModel(Settings):
"""
provider_tokens_set: dict[str, bool] | None = None
llm_api_key_set: bool

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "openhands-ai"
version = "0.30.1"
version = "0.31.0"
description = "OpenHands: Code Less, Make More"
authors = ["OpenHands"]
license = "MIT"
@@ -97,7 +97,6 @@ reportlab = "*"
[tool.coverage.run]
concurrency = ["gevent"]
[tool.poetry.group.runtime.dependencies]
jupyterlab = "*"
notebook = "*"
@@ -126,7 +125,6 @@ ignore = ["D1"]
[tool.ruff.lint.pydocstyle]
convention = "google"
[tool.poetry.group.evaluation.dependencies]
streamlit = "*"
whatthepatch = "*"