Compare commits

..

17 Commits

Author SHA1 Message Date
rohitvinodmalhotra@gmail.com 0fb76b2228 Update uv.lock 2025-10-13 17:05:07 -04:00
Rohit Malhotra dadb3c4a80 Merge branch 'main' into rel-cli-1.0.1 2025-10-13 17:04:42 -04:00
Rohit Malhotra 2640d43159 Fix API key disappearing bug when updating CLI settings (#11351)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-10-13 21:02:58 +00:00
rohitvinodmalhotra@gmail.com d8b6b0a0c7 automatic version discovery 2025-10-13 15:32:01 -04:00
rohitvinodmalhotra@gmail.com db4f0ecf4f bump package 2025-10-13 15:11:27 -04:00
Rohit Malhotra 609fefc1b6 Fix CLI binary GLIBC compatibility for older Linux systems (#11337)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-10-13 18:52:52 +00:00
Rohit Malhotra 5db0d495d4 RM CLI version on opening page (#11347) 2025-10-13 18:33:57 +00:00
Rohit Malhotra 60fa7b3d01 [Hotfix, CLI(V1)]: Prevent crashing cli when confirmation mode disabled (#11343) 2025-10-13 17:43:22 +00:00
Rohit Malhotra cca2a55166 Fix openhands CLI executable entry point in pyproject.toml (#11338)
Co-authored-by: openhands <openhands@all-hands.dev>
2025-10-13 15:04:46 +00:00
Ryan H. Tran c5e58572d5 fix(cli): escape action content before passing to HTML (#11333) 2025-10-13 22:02:26 +07:00
Alona baaa41ed99 feat: Add Bitbucket Resolver templates (#10880) 2025-10-13 10:23:24 -04:00
Kevin Musgrave 19bae5ac0f feat(evaluation): Add placeholders to swe_gpt4.j2 (#11228)
Co-authored-by: Graham Neubig <neubig@gmail.com>
2025-10-13 22:15:05 +08:00
rstar327 93e1cd44c6 fix: (frontend) clean up unsed error variable in try/catch block (#11325) 2025-10-13 14:13:11 +00:00
llamantino c0ce78c64a fix: remove the hardcoded 5-minute timeout from the docker pull command (#11322) 2025-10-13 10:00:10 -04:00
Bogdan Petković 399bf92ed1 Fix: Correct rename detection in apply_patch to check per-diff instead of full patch (#10913)
Signed-off-by: Bogdan Petkovic <bogdan@fatdragon.dev>
Co-authored-by: Bogdan Petkovic <bogdan@fatdragon.dev>
2025-10-13 09:47:01 -04:00
Ray Myers 2bbe15a329 chore - CI check migrations are in sync and warn (#10946) 2025-10-10 15:19:00 -05:00
mamoodi 6f22092d07 Release 0.59.0 (#11319) 2025-10-10 15:31:38 -04:00
42 changed files with 303 additions and 159 deletions
@@ -21,27 +21,19 @@ concurrency:
cancel-in-progress: true
jobs:
build-and-test-binary:
name: Build and test binary executable
build-binary:
name: Build binary executable
strategy:
matrix:
include:
# Linux x86_64
- os: ubuntu-latest
arch: x86_64
# Build on Ubuntu 22.04 for maximum GLIBC compatibility (GLIBC 2.31)
- os: ubuntu-22.04
platform: linux
# Linux ARM64
- os: ubuntu-latest-arm64
arch: arm64
platform: linux
# macOS x86_64 (Intel)
- os: macos-13
arch: x86_64
platform: macos
# macOS ARM64 (Apple Silicon)
- os: macos-latest
arch: arm64
artifact_name: openhands-cli-linux
# Build on macOS for macOS users
- os: macos-15
platform: macos
artifact_name: openhands-cli-macos
runs-on: ${{ matrix.os }}
steps:
@@ -68,14 +60,7 @@ jobs:
- name: Build binary executable
working-directory: openhands-cli
run: |
# Set build arguments based on platform and architecture
BUILD_ARGS="--install-pyinstaller"
if [ "${{ matrix.platform }}" = "macos" ]; then
BUILD_ARGS="$BUILD_ARGS --target-arch ${{ matrix.arch }}"
fi
echo "🔨 Building with args: $BUILD_ARGS"
./build.sh $BUILD_ARGS | tee output.log
./build.sh --install-pyinstaller | tee output.log
echo "Full output:"
cat output.log
@@ -86,18 +71,17 @@ jobs:
echo "✅ Build & test finished without ❌ markers"
- name: Upload binary artifact (for releases only)
if: startsWith(github.ref, 'refs/tags/')
- name: Upload binary artifact
uses: actions/upload-artifact@v4
with:
name: openhands-cli-${{ matrix.platform }}-${{ matrix.arch }}
name: ${{ matrix.artifact_name }}
path: openhands-cli/dist/openhands*
retention-days: 30
create-github-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: build-and-test-binary
needs: build-binary
if: startsWith(github.ref, 'refs/tags/')
steps:
- name: Checkout repository
@@ -111,24 +95,13 @@ jobs:
- name: Prepare release assets
run: |
mkdir -p release-assets
# Rename binaries to include platform and architecture in filename
for artifact_dir in artifacts/openhands-cli-*; do
if [ -d "$artifact_dir" ]; then
# Extract platform and arch from directory name
# Format: openhands-cli-{platform}-{arch}
dir_name=$(basename "$artifact_dir")
platform_arch=${dir_name#openhands-cli-}
if [ -f "$artifact_dir/openhands" ]; then
cp "$artifact_dir/openhands" "release-assets/openhands-$platform_arch"
echo "✅ Copied $artifact_dir/openhands to release-assets/openhands-$platform_arch"
else
echo "⚠️ No openhands binary found in $artifact_dir"
fi
fi
done
echo "📁 Release assets prepared:"
# Copy binaries with appropriate names for release
if [ -f artifacts/openhands-cli-linux/openhands ]; then
cp artifacts/openhands-cli-linux/openhands release-assets/openhands-linux
fi
if [ -f artifacts/openhands-cli-macos/openhands ]; then
cp artifacts/openhands-cli-macos/openhands release-assets/openhands-macos
fi
ls -la release-assets/
- name: Create GitHub Release
@@ -0,0 +1,52 @@
name: Enterprise Check Migrations
on:
pull_request:
paths:
- 'enterprise/migrations/**'
jobs:
check-sync:
runs-on: ubuntu-latest
steps:
- name: Checkout PR branch
uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- name: Fetch base branch
run: git fetch origin ${{ github.event.pull_request.base.ref }}
- name: Check if base branch is ancestor of PR
id: check_up_to_date
shell: bash
run: |
BASE="origin/${{ github.event.pull_request.base.ref }}"
HEAD="${{ github.event.pull_request.head.sha }}"
if git merge-base --is-ancestor "$BASE" "$HEAD"; then
echo "We're up to date with base $BASE"
exit 0
else
echo "NOT up to date with base $BASE"
exit 1
fi
- name: Find Comment
uses: peter-evans/find-comment@v3
id: find-comment
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: |
⚠️ This PR contains **migrations**
- name: Comment warning on PR
uses: peter-evans/create-or-update-comment@v4
with:
issue-number: ${{ github.event.pull_request.number }}
comment-id: ${{ steps.find-comment.outputs.comment-id }}
edit-mode: replace
body: |
⚠️ This PR contains **migrations**. Please synchronize before merging to prevent conflicts.
+1 -1
View File
@@ -71,7 +71,7 @@ jobs:
run: pip install pre-commit==4.2.0
- name: Run pre-commit hooks
working-directory: ./enterprise
run: pre-commit run --all-files --config ./dev_config/python/.pre-commit-config.yaml
run: pre-commit run --all-files --show-diff-on-failure --config ./dev_config/python/.pre-commit-config.yaml
lint-cli-python:
name: Lint CLI python
+1 -1
View File
@@ -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/all-hands-ai/runtime:0.58-nikolaik`
Example: `export SANDBOX_RUNTIME_CONTAINER_IMAGE=ghcr.io/all-hands-ai/runtime:0.59-nikolaik`
## Develop inside Docker container
+3 -3
View File
@@ -76,17 +76,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.all-hands.dev/all-hands-ai/runtime:0.58-nikolaik
docker pull docker.all-hands.dev/all-hands-ai/runtime:0.59-nikolaik
docker run -it --rm --pull=always \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.58-nikolaik \
-e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:0.59-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.all-hands.dev/all-hands-ai/openhands:0.58
docker.all-hands.dev/all-hands-ai/openhands:0.59
```
</details>
+1 -1
View File
@@ -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/all-hands-ai/runtime:0.58-nikolaik}
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-ghcr.io/all-hands-ai/runtime:0.59-nikolaik}
- SANDBOX_USER_ID=${SANDBOX_USER_ID:-1234}
- WORKSPACE_MOUNT_PATH=${WORKSPACE_BASE:-$PWD/workspace}
ports:
+1 -1
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.58-nikolaik}
- SANDBOX_RUNTIME_CONTAINER_IMAGE=${SANDBOX_RUNTIME_CONTAINER_IMAGE:-docker.all-hands.dev/all-hands-ai/runtime:0.59-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:
+5
View File
@@ -0,0 +1,5 @@
# Enterprise Migrations
## Migration conflicts
OpenHands PRs can fall out of sync with `main` quickly. When adding a migration, it's safest to sync the PR with main before merging to ensure you are caught up to any others that have been added.
@@ -16,6 +16,10 @@ At the end, you must test your code rigorously using the tools provided, and do
You MUST plan extensively before each function call, and reflect extensively on the outcomes of the previous function calls. DO NOT do this entire process by making function calls only, as this can impair your ability to solve the problem and think insightfully.
## Issue Description
{{ instance.problem_statement }}
# Workflow
## High-Level Problem Solving Strategy
@@ -73,6 +77,7 @@ Carefully read the issue and think hard about a plan to solve it before coding.
## 8. Final Reflection and Additional Testing
- Reflect carefully on the original intent of the user and the problem statement.
- Compare your changes with the base commit {{ instance.base_commit }} to ensure minimal and focused modifications.
- Think about potential edge cases or scenarios that may not be covered by existing tests.
- Write additional tests that would need to pass to fully validate the correctness of your solution.
- Run these new tests and ensure they all pass.
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "openhands-frontend",
"version": "0.58.0",
"version": "0.59.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "openhands-frontend",
"version": "0.58.0",
"version": "0.59.0",
"dependencies": {
"@heroui/react": "^2.8.4",
"@heroui/use-infinite-scroll": "^2.2.11",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "openhands-frontend",
"version": "0.58.0",
"version": "0.59.0",
"private": true,
"type": "module",
"engines": {
@@ -121,7 +121,7 @@ class ConversationService {
reason?: string;
}>(url);
return data;
} catch (error) {
} catch {
// Error checking if feedback exists
return { exists: false };
}
@@ -120,7 +120,7 @@ export function InteractiveChatBox({
// Step 5: Handle failed results
handleFailedFiles(fileResults, imageResults);
} catch (error) {
} catch {
// Clear loading states and show error
clearLoadingStates(validFiles, validImages);
displayErrorToast("An unexpected error occurred while processing files");
@@ -90,7 +90,7 @@ export function ConversationCard({
}
}
// VS Code URL not available
} catch (error) {
} catch {
// Failed to fetch VS Code URL
}
}
@@ -23,7 +23,7 @@ export function useUrlSearch(inputValue: string, provider: Provider) {
);
setUrlSearchResults(repositories);
} catch (error) {
} catch {
setUrlSearchResults([]);
} finally {
setIsUrlSearchLoading(false);
@@ -28,7 +28,7 @@ export function CancelSubscriptionModal({
await cancelSubscriptionMutation.mutateAsync();
displaySuccessToast(t(I18nKey.PAYMENT$SUBSCRIPTION_CANCELLED));
onClose();
} catch (error) {
} catch {
displayErrorToast(t(I18nKey.ERROR$GENERIC));
}
};
@@ -39,7 +39,7 @@ export function CreateApiKeyModal({
onKeyCreated(newKey);
displaySuccessToast(t(I18nKey.SETTINGS$API_KEY_CREATED));
setNewKeyName("");
} catch (error) {
} catch {
displayErrorToast(t(I18nKey.ERROR$GENERIC));
}
};
@@ -32,7 +32,7 @@ export function DeleteApiKeyModal({
await deleteApiKeyMutation.mutateAsync(keyToDelete.id);
displaySuccessToast(t(I18nKey.SETTINGS$API_KEY_DELETED));
onClose();
} catch (error) {
} catch {
displayErrorToast(t(I18nKey.ERROR$GENERIC));
}
};
@@ -275,7 +275,7 @@ export function ConversationSubscriptionsProvider({
setActiveConversationIds((prev) =>
prev.includes(conversationId) ? prev : [...prev, conversationId],
);
} catch (error) {
} catch {
// Clean up the event handler if there was an error
delete eventHandlersRef.current[conversationId];
}
+1 -1
View File
@@ -25,7 +25,7 @@ function PosthogInit() {
try {
const config = await OptionService.getConfig();
setPosthogClientKey(config.POSTHOG_CLIENT_KEY);
} catch (error) {
} catch {
displayErrorToast("Error fetching PostHog client key");
}
})();
@@ -140,7 +140,7 @@ export function useConversationNameContextMenu({
}
}
// VS Code URL not available
} catch (error) {
} catch {
// Failed to fetch VS Code URL
}
}
+1 -1
View File
@@ -24,7 +24,7 @@ export function transformVSCodeUrl(vsCodeUrl: string | null): string | null {
}
return vsCodeUrl;
} catch (error) {
} catch {
// Silently handle the error and return the original URL
return vsCodeUrl;
}
+3 -35
View File
@@ -72,7 +72,6 @@ def check_pyinstaller() -> bool:
def build_executable(
spec_file: str = 'openhands.spec',
clean: bool = True,
target_arch: str = None,
) -> bool:
"""Build the executable using PyInstaller."""
if clean:
@@ -84,27 +83,8 @@ def build_executable(
print(f'🔨 Building executable using {spec_file}...')
# Handle target architecture for macOS by modifying the spec file
original_spec_content = None
if target_arch and sys.platform == 'darwin':
print(f'🎯 Building for macOS target architecture: {target_arch}')
# Read the original spec file
with open(spec_file, 'r') as f:
original_spec_content = f.read()
# Replace target_arch=None with target_arch='<arch>'
modified_spec_content = original_spec_content.replace(
'target_arch=None',
f"target_arch='{target_arch}'"
)
# Write the modified spec file
with open(spec_file, 'w') as f:
f.write(modified_spec_content)
try:
# Run PyInstaller with uv (no --target-arch flag needed with spec file)
# Run PyInstaller with uv
cmd = ['uv', 'run', 'pyinstaller', spec_file, '--clean']
print(f'Running: {" ".join(cmd)}')
@@ -133,12 +113,6 @@ def build_executable(
if e.stderr:
print('STDERR:', e.stderr)
return False
finally:
# Restore the original spec file if we modified it
if original_spec_content is not None:
with open(spec_file, 'w') as f:
f.write(original_spec_content)
print(f'🔄 Restored original {spec_file}')
# =================================================
@@ -190,7 +164,7 @@ def test_executable() -> bool:
)
# --- Wait for welcome ---
deadline = boot_start + 30
deadline = boot_start + 60
saw_welcome = False
captured = []
@@ -280,10 +254,6 @@ def main() -> int:
action='store_true',
help='Install PyInstaller using uv before building',
)
parser.add_argument(
'--target-arch',
help='Target architecture for macOS builds (x86_64, arm64, universal2)',
)
parser.add_argument(
'--no-build', action='store_true', help='Skip testing the built executable'
@@ -300,9 +270,7 @@ def main() -> int:
return 1
# Build the executable
if not args.no_build and not build_executable(
args.spec, clean=not args.no_clean, target_arch=args.target_arch
):
if not args.no_build and not build_executable(args.spec, clean=not args.no_clean):
return 1
# Test the executable
+7 -2
View File
@@ -1,3 +1,8 @@
"""OpenHands CLI package."""
"""OpenHands package."""
__version__ = '0.1.0'
from importlib.metadata import version, PackageNotFoundError
try:
__version__ = version("openhands")
except PackageNotFoundError:
__version__ = "0.0.0"
@@ -54,6 +54,7 @@ def _print_exit_hint(conversation_id: str) -> None:
)
def run_cli_entry(resume_conversation_id: str | None = None) -> None:
"""Run the agent chat session using the agent SDK.
+1 -10
View File
@@ -113,21 +113,12 @@ def launch_gui_server(mount_cwd: bool = False, gpu: bool = False) -> None:
pull_cmd = ['docker', 'pull', runtime_image]
print_formatted_text(HTML(_format_docker_command_for_logging(pull_cmd)))
try:
subprocess.run(
pull_cmd,
check=True,
timeout=300, # 5 minutes timeout
)
subprocess.run(pull_cmd, check=True)
except subprocess.CalledProcessError:
print_formatted_text(
HTML('<ansired>❌ Failed to pull runtime image.</ansired>')
)
sys.exit(1)
except subprocess.TimeoutExpired:
print_formatted_text(
HTML('<ansired>❌ Timeout while pulling runtime image.</ansired>')
)
sys.exit(1)
print_formatted_text('')
print_formatted_text(
-2
View File
@@ -57,8 +57,6 @@ def display_banner(conversation_id: str, resume: bool = False) -> None:
style=DEFAULT_STYLE,
)
print_formatted_text(HTML(f'<grey>OpenHands CLI v{__version__}</grey>'))
print_formatted_text('')
if not resume:
print_formatted_text(
@@ -1,3 +1,4 @@
import html
from prompt_toolkit import HTML, print_formatted_text
from openhands.sdk.security.confirmation_policy import (
@@ -37,7 +38,7 @@ def ask_user_confirmation(
or '[unknown action]'
)
print_formatted_text(
HTML(f'<grey> {i}. {tool_name}: {action_content}...</grey>')
HTML(f'<grey> {i}. {tool_name}: {html.escape(action_content)}...</grey>')
)
question = 'Choose an option:'
@@ -123,9 +123,15 @@ def prompt_api_key(
validator = NonEmptyValueValidator()
question = helper_text + step_counter.next_step(question)
return cli_text_input(
user_input = cli_text_input(
question, escapable=escapable, validator=validator, is_password=True
)
# If user pressed ENTER with existing key (empty input), return the existing key
if existing_api_key and not user_input.strip():
return existing_api_key.get_secret_value()
return user_input
# Advanced settings functions
+4 -5
View File
@@ -4,7 +4,7 @@ requires = [ "hatchling>=1.25" ]
[project]
name = "openhands"
version = "1.0.0"
version = "1.0.1"
description = "OpenHands CLI - Terminal User Interface for OpenHands AI Agent"
readme = "README.md"
license = { text = "MIT" }
@@ -22,8 +22,7 @@ dependencies = [
"typer>=0.17.4",
]
# Dev-only tools with uv groups: `uv sync --group dev`
scripts.openhands = "openhands_cli.simple_main:main"
scripts = { openhands = "openhands_cli.simple_main:main" }
[dependency-groups]
# Hatchling wheel target: include the package directory
@@ -96,5 +95,5 @@ disallow_untyped_defs = true
ignore_missing_imports = true
[tool.uv.sources]
openhands-sdk = { git = "https://github.com/All-Hands-AI/agent-sdk.git", subdirectory = "openhands/sdk", rev = "189979a5013751aa86852ab41afe9a79555e62ac" }
openhands-tools = { git = "https://github.com/All-Hands-AI/agent-sdk.git", subdirectory = "openhands/tools", rev = "189979a5013751aa86852ab41afe9a79555e62ac" }
openhands-sdk = { git = "https://github.com/All-Hands-AI/agent-sdk.git", subdirectory = "openhands/sdk", rev = "50b094a92817e448ec4352d2950df4f19edd5a9f" }
openhands-tools = { git = "https://github.com/All-Hands-AI/agent-sdk.git", subdirectory = "openhands/tools", rev = "50b094a92817e448ec4352d2950df4f19edd5a9f" }
@@ -0,0 +1,56 @@
"""Test for API key preservation bug when updating settings."""
from unittest.mock import patch
import pytest
from pydantic import SecretStr
from openhands_cli.user_actions.settings_action import prompt_api_key
from openhands_cli.tui.utils import StepCounter
def test_api_key_preservation_when_user_presses_enter():
"""Test that API key is preserved when user presses ENTER to keep current key.
This test replicates the bug where API keys disappear when updating settings.
When a user presses ENTER to keep the current API key, the function should
return the existing API key, not an empty string.
"""
step_counter = StepCounter(1)
existing_api_key = SecretStr("sk-existing-key-123")
# Mock cli_text_input to return empty string (simulating user pressing ENTER)
with patch('openhands_cli.user_actions.settings_action.cli_text_input', return_value=''):
result = prompt_api_key(
step_counter=step_counter,
provider='openai',
existing_api_key=existing_api_key,
escapable=True
)
# The bug: result is empty string instead of the existing key
# This test will fail initially, demonstrating the bug
assert result == existing_api_key.get_secret_value(), (
f"Expected existing API key '{existing_api_key.get_secret_value()}' "
f"but got '{result}'. API key should be preserved when user presses ENTER."
)
def test_api_key_update_when_user_enters_new_key():
"""Test that API key is updated when user enters a new key."""
step_counter = StepCounter(1)
existing_api_key = SecretStr("sk-existing-key-123")
new_api_key = "sk-new-key-456"
# Mock cli_text_input to return new API key
with patch('openhands_cli.user_actions.settings_action.cli_text_input', return_value=new_api_key):
result = prompt_api_key(
step_counter=step_counter,
provider='openai',
existing_api_key=existing_api_key,
escapable=True
)
# Should return the new API key
assert result == new_api_key
-2
View File
@@ -111,8 +111,6 @@ class TestLaunchGuiServer:
[
# Docker pull failure
(subprocess.CalledProcessError(1, 'docker pull'), None, 1, False, False),
# Docker pull timeout
(subprocess.TimeoutExpired('docker pull', 300), None, 1, False, False),
# Docker run failure
(MagicMock(returncode=0), subprocess.CalledProcessError(1, 'docker run'), 1, False, False),
# KeyboardInterrupt during run
+32 -21
View File
@@ -660,18 +660,32 @@ wheels = [
[[package]]
name = "fastuuid"
version = "0.12.0"
version = "0.13.5"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/19/17/13146a1e916bd2971d0a58db5e0a4ad23efdd49f78f33ac871c161f8007b/fastuuid-0.12.0.tar.gz", hash = "sha256:d0bd4e5b35aad2826403f4411937c89e7c88857b1513fe10f696544c03e9bd8e", size = 19180, upload-time = "2025-01-27T18:04:14.387Z" }
sdist = { url = "https://files.pythonhosted.org/packages/15/80/3c16a1edad2e6cd82fbd15ac998cc1b881f478bf1f80ca717d941c441874/fastuuid-0.13.5.tar.gz", hash = "sha256:d4976821ab424d41542e1ea39bc828a9d454c3f8a04067c06fca123c5b95a1a1", size = 18255, upload-time = "2025-09-26T09:05:38.281Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f6/28/442e79d6219b90208cb243ac01db05d89cc4fdf8ecd563fb89476baf7122/fastuuid-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:328694a573fe9dce556b0b70c9d03776786801e028d82f0b6d9db1cb0521b4d1", size = 247372, upload-time = "2025-01-27T18:03:40.967Z" },
{ url = "https://files.pythonhosted.org/packages/40/eb/e0fd56890970ca7a9ec0d116844580988b692b1a749ac38e0c39e1dbdf23/fastuuid-0.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02acaea2c955bb2035a7d8e7b3fba8bd623b03746ae278e5fa932ef54c702f9f", size = 258200, upload-time = "2025-01-27T18:04:12.138Z" },
{ url = "https://files.pythonhosted.org/packages/f5/3c/4b30e376e65597a51a3dc929461a0dec77c8aec5d41d930f482b8f43e781/fastuuid-0.12.0-cp312-cp312-manylinux_2_34_x86_64.whl", hash = "sha256:ed9f449cba8cf16cced252521aee06e633d50ec48c807683f21cc1d89e193eb0", size = 278446, upload-time = "2025-01-27T18:04:15.877Z" },
{ url = "https://files.pythonhosted.org/packages/fe/96/cc5975fd23d2197b3e29f650a7a9beddce8993eaf934fa4ac595b77bb71f/fastuuid-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:0df2ea4c9db96fd8f4fa38d0e88e309b3e56f8fd03675a2f6958a5b082a0c1e4", size = 157185, upload-time = "2025-01-27T18:06:19.21Z" },
{ url = "https://files.pythonhosted.org/packages/a9/e8/d2bb4f19e5ee15f6f8e3192a54a897678314151aa17d0fb766d2c2cbc03d/fastuuid-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7fe2407316a04ee8f06d3dbc7eae396d0a86591d92bafe2ca32fce23b1145786", size = 247512, upload-time = "2025-01-27T18:04:08.115Z" },
{ url = "https://files.pythonhosted.org/packages/bc/53/25e811d92fd60f5c65e098c3b68bd8f1a35e4abb6b77a153025115b680de/fastuuid-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b31dd488d0778c36f8279b306dc92a42f16904cba54acca71e107d65b60b0c", size = 258257, upload-time = "2025-01-27T18:03:56.408Z" },
{ url = "https://files.pythonhosted.org/packages/10/23/73618e7793ea0b619caae2accd9e93e60da38dd78dd425002d319152ef2f/fastuuid-0.12.0-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:b19361ee649365eefc717ec08005972d3d1eb9ee39908022d98e3bfa9da59e37", size = 278559, upload-time = "2025-01-27T18:03:58.661Z" },
{ url = "https://files.pythonhosted.org/packages/e4/41/6317ecfc4757d5f2a604e5d3993f353ba7aee85fa75ad8b86fce6fc2fa40/fastuuid-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:8fc66b11423e6f3e1937385f655bedd67aebe56a3dcec0cb835351cfe7d358c9", size = 157276, upload-time = "2025-01-27T18:06:39.245Z" },
{ url = "https://files.pythonhosted.org/packages/21/36/434f137c5970cac19e57834e1f7680e85301619d49891618c00666700c61/fastuuid-0.13.5-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:35fe8045e866bc6846f8de6fa05acb1de0c32478048484a995e96d31e21dff2a", size = 494638, upload-time = "2025-09-26T09:14:58.695Z" },
{ url = "https://files.pythonhosted.org/packages/ca/3c/083de2ac007b2b305523b9c006dba5051e5afd87a626ef1a39f76e2c6b82/fastuuid-0.13.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:02a460333f52d731a006d18a52ef6fcb2d295a1f5b1a5938d30744191b2f77b7", size = 253138, upload-time = "2025-09-26T09:13:33.283Z" },
{ url = "https://files.pythonhosted.org/packages/73/5e/630cffa1c8775db526e39e9e4c5c7db0c27be0786bb21ba82c912ae19f63/fastuuid-0.13.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:74b0e4f8c307b9f477a5d7284db4431ce53a3c1e3f4173db7a97db18564a6202", size = 244521, upload-time = "2025-09-26T09:14:40.682Z" },
{ url = "https://files.pythonhosted.org/packages/4d/51/55d78705f4fbdadf88fb40f382f508d6c7a4941ceddd7825fafebb4cc778/fastuuid-0.13.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6955a99ef455c2986f3851f4e0ccc35dec56ac1a7720f2b92e88a75d6684512e", size = 271557, upload-time = "2025-09-26T09:15:09.75Z" },
{ url = "https://files.pythonhosted.org/packages/6a/2b/1b89e90a8635e5587ccdbbeb169c590672ce7637880f2c047482a0359950/fastuuid-0.13.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f10c77b826738c1a27dcdaa92ea4dc1ec9d869748a99e1fde54f1379553d4854", size = 272334, upload-time = "2025-09-26T09:07:48.865Z" },
{ url = "https://files.pythonhosted.org/packages/0c/06/4c8207894eeb30414999e5c3f66ac039bc4003437eb4060d8a1bceb4cc6f/fastuuid-0.13.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb25dccbeb249d16d5e664f65f17ebec05136821d5ef462c4110e3f76b86fb86", size = 290594, upload-time = "2025-09-26T09:12:54.124Z" },
{ url = "https://files.pythonhosted.org/packages/50/69/96d221931a31d77a47cc2487bdfacfb3091edfc2e7a04b1795df1aec05df/fastuuid-0.13.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a5becc646a3eeafb76ce0a6783ba190cd182e3790a8b2c78ca9db2b5e87af952", size = 452835, upload-time = "2025-09-26T09:14:00.994Z" },
{ url = "https://files.pythonhosted.org/packages/25/ef/bf045f0a47dcec96247497ef3f7a31d86ebc074330e2dccc34b8dbc0468a/fastuuid-0.13.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:69b34363752d06e9bb0dbdf02ae391ec56ac948c6f2eb00be90dad68e80774b9", size = 468225, upload-time = "2025-09-26T09:13:38.585Z" },
{ url = "https://files.pythonhosted.org/packages/30/46/4817ab5a3778927155a4bde92540d4c4fa996161ec8b8e080c8928b0984e/fastuuid-0.13.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57d0768afcad0eab8770c9b8cf904716bd3c547e8b9a4e755ee8a673b060a3a3", size = 444907, upload-time = "2025-09-26T09:14:30.163Z" },
{ url = "https://files.pythonhosted.org/packages/80/27/ab284117ce4dc9b356a7196bdbf220510285f201d27f1f078592cdc8187b/fastuuid-0.13.5-cp312-cp312-win32.whl", hash = "sha256:8ac6c6f5129d52eaa6ef9ea4b6e2f7c69468a053f3ab8e439661186b9c06bb85", size = 145415, upload-time = "2025-09-26T09:08:59.494Z" },
{ url = "https://files.pythonhosted.org/packages/f4/0c/f970a4222773b248931819f8940800b760283216ca3dda173ed027e94bdd/fastuuid-0.13.5-cp312-cp312-win_amd64.whl", hash = "sha256:ad630e97715beefef07ec37c9c162336e500400774e2c1cbe1a0df6f80d15b9a", size = 150840, upload-time = "2025-09-26T09:13:46.115Z" },
{ url = "https://files.pythonhosted.org/packages/4f/62/74fc53f6e04a4dc5b36c34e4e679f85a4c14eec800dcdb0f2c14b5442217/fastuuid-0.13.5-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:ea17dfd35e0e91920a35d91e65e5f9c9d1985db55ac4ff2f1667a0f61189cefa", size = 494678, upload-time = "2025-09-26T09:14:30.908Z" },
{ url = "https://files.pythonhosted.org/packages/09/ba/f28b9b7045738a8bfccfb9cd6aff4b91fce2669e6b383a48b0694ee9b3ff/fastuuid-0.13.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:be6ad91e5fefbcc2a4b478858a2715e386d405834ea3ae337c3b6b95cc0e47d6", size = 253162, upload-time = "2025-09-26T09:13:35.879Z" },
{ url = "https://files.pythonhosted.org/packages/b1/18/13fac89cb4c9f0cd7e81a9154a77ecebcc95d2b03477aa91d4d50f7227ee/fastuuid-0.13.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ea6df13a306aab3e0439d58c312ff1e6f4f07f09f667579679239b4a6121f64a", size = 244546, upload-time = "2025-09-26T09:14:58.13Z" },
{ url = "https://files.pythonhosted.org/packages/04/bf/9691167804d59411cc4269841df949f6dd5e76452ab10dcfcd1dbe04c5bc/fastuuid-0.13.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2354c1996d3cf12dc2ba3752e2c4d6edc46e1a38c63893146777b1939f3062d4", size = 271528, upload-time = "2025-09-26T09:14:48.996Z" },
{ url = "https://files.pythonhosted.org/packages/a9/b5/7a75a03d1c7aa0b6d573032fcca39391f0aef7f2caabeeb45a672bc0bd3c/fastuuid-0.13.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6cf9b7469fc26d1f9b1c43ac4b192e219e85b88fdf81d71aa755a6c08c8a817", size = 272292, upload-time = "2025-09-26T09:14:42.82Z" },
{ url = "https://files.pythonhosted.org/packages/c0/db/fa0f16cbf76e6880599533af4ef01bb586949c5320612e9d884eff13e603/fastuuid-0.13.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92ba539170097b9047551375f1ca09d8d2b4aefcc79eeae3e1c43fe49b42072e", size = 290466, upload-time = "2025-09-26T09:08:33.161Z" },
{ url = "https://files.pythonhosted.org/packages/1e/02/6b8c45bfbc8500994dd94edba7f59555f9683c4d8c9a164ae1d25d03c7c7/fastuuid-0.13.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:dbb81d05617bc2970765c1ad82db7e8716f6a2b7a361a14b83de5b9240ade448", size = 452838, upload-time = "2025-09-26T09:13:44.747Z" },
{ url = "https://files.pythonhosted.org/packages/27/12/85d95a84f265b888e8eb9f9e2b5aaf331e8be60c0a7060146364b3544b6a/fastuuid-0.13.5-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:d973bd6bf9d754d3cca874714ac0a6b22a47f239fb3d3c8687569db05aac3471", size = 468149, upload-time = "2025-09-26T09:13:18.712Z" },
{ url = "https://files.pythonhosted.org/packages/ad/da/dd9a137e9ea707e883c92470113a432233482ec9ad3e9b99c4defc4904e6/fastuuid-0.13.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e725ceef79486423f05ee657634d4b4c1ca5fb2c8a94e0708f5d6356a83f2a83", size = 444933, upload-time = "2025-09-26T09:14:09.494Z" },
{ url = "https://files.pythonhosted.org/packages/12/f4/ab363d7f4ac3989691e2dc5ae2d8391cfb0b4169e52ef7fa0ac363e936f0/fastuuid-0.13.5-cp313-cp313-win32.whl", hash = "sha256:a1c430a332ead0b2674f1ef71b17f43b8139ec5a4201182766a21f131a31e021", size = 145462, upload-time = "2025-09-26T09:14:15.105Z" },
{ url = "https://files.pythonhosted.org/packages/aa/8a/52eb77d9c294a54caa0d2d8cc9f906207aa6d916a22de963687ab6db8b86/fastuuid-0.13.5-cp313-cp313-win_amd64.whl", hash = "sha256:241fdd362fd96e6b337db62a65dd7cb3dfac20adf854573247a47510e192db6f", size = 150923, upload-time = "2025-09-26T09:13:03.923Z" },
]
[[package]]
@@ -1266,8 +1280,8 @@ wheels = [
[[package]]
name = "litellm"
version = "1.76.2"
source = { registry = "https://pypi.org/simple" }
version = "1.77.7"
source = { git = "https://github.com/BerriAI/litellm.git?rev=v1.77.7.dev9#763d2f8ccdd8412dbe6d4ac0e136d9ac34dcd4c0" }
dependencies = [
{ name = "aiohttp" },
{ name = "click" },
@@ -1282,10 +1296,6 @@ dependencies = [
{ name = "tiktoken" },
{ name = "tokenizers" },
]
sdist = { url = "https://files.pythonhosted.org/packages/75/a3/f7c00c660972eed1ba5ed53771ac9b4235e7fb1dc410e91d35aff2778ae7/litellm-1.76.2.tar.gz", hash = "sha256:fc7af111fa0f06943d8dbebed73f88000f9902f0d0ee0882c57d0bd5c1a37ecb", size = 10189238, upload-time = "2025-09-04T00:25:09.472Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/79/f4/980cc81c21424026dcb48a541654fd6f4286891825a3d0dd51f02b65cbc3/litellm-1.76.2-py3-none-any.whl", hash = "sha256:a9a2ef64a598b5b4ae245f1de6afc400856477cd6f708ff633d95e2275605a45", size = 8973847, upload-time = "2025-09-04T00:25:05.353Z" },
]
[[package]]
name = "macholib"
@@ -1615,7 +1625,7 @@ wheels = [
[[package]]
name = "openhands"
version = "0.1.0"
version = "1.0.1"
source = { editable = "." }
dependencies = [
{ name = "openhands-sdk" },
@@ -1642,8 +1652,8 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "openhands-sdk", git = "https://github.com/All-Hands-AI/agent-sdk.git?subdirectory=openhands%2Fsdk&rev=189979a5013751aa86852ab41afe9a79555e62ac" },
{ name = "openhands-tools", git = "https://github.com/All-Hands-AI/agent-sdk.git?subdirectory=openhands%2Ftools&rev=189979a5013751aa86852ab41afe9a79555e62ac" },
{ name = "openhands-sdk", git = "https://github.com/All-Hands-AI/agent-sdk.git?subdirectory=openhands%2Fsdk&rev=50b094a92817e448ec4352d2950df4f19edd5a9f" },
{ name = "openhands-tools", git = "https://github.com/All-Hands-AI/agent-sdk.git?subdirectory=openhands%2Ftools&rev=50b094a92817e448ec4352d2950df4f19edd5a9f" },
{ name = "prompt-toolkit", specifier = ">=3" },
{ name = "typer", specifier = ">=0.17.4" },
]
@@ -1667,9 +1677,10 @@ dev = [
[[package]]
name = "openhands-sdk"
version = "1.0.0"
source = { git = "https://github.com/All-Hands-AI/agent-sdk.git?subdirectory=openhands%2Fsdk&rev=189979a5013751aa86852ab41afe9a79555e62ac#189979a5013751aa86852ab41afe9a79555e62ac" }
source = { git = "https://github.com/All-Hands-AI/agent-sdk.git?subdirectory=openhands%2Fsdk&rev=50b094a92817e448ec4352d2950df4f19edd5a9f#50b094a92817e448ec4352d2950df4f19edd5a9f" }
dependencies = [
{ name = "fastmcp" },
{ name = "httpx" },
{ name = "litellm" },
{ name = "pydantic" },
{ name = "python-frontmatter" },
@@ -1681,7 +1692,7 @@ dependencies = [
[[package]]
name = "openhands-tools"
version = "1.0.0"
source = { git = "https://github.com/All-Hands-AI/agent-sdk.git?subdirectory=openhands%2Ftools&rev=189979a5013751aa86852ab41afe9a79555e62ac#189979a5013751aa86852ab41afe9a79555e62ac" }
source = { git = "https://github.com/All-Hands-AI/agent-sdk.git?subdirectory=openhands%2Ftools&rev=50b094a92817e448ec4352d2950df4f19edd5a9f#50b094a92817e448ec4352d2950df4f19edd5a9f" }
dependencies = [
{ name = "bashlex" },
{ name = "binaryornot" },
+1 -10
View File
@@ -103,21 +103,12 @@ def launch_gui_server(mount_cwd: bool = False, gpu: bool = False) -> None:
pull_cmd = ['docker', 'pull', runtime_image]
print_formatted_text(HTML(_format_docker_command_for_logging(pull_cmd)))
try:
subprocess.run(
pull_cmd,
check=True,
timeout=300, # 5 minutes timeout
)
subprocess.run(pull_cmd, check=True)
except subprocess.CalledProcessError:
print_formatted_text(
HTML('<ansired>❌ Failed to pull runtime image.</ansired>')
)
sys.exit(1)
except subprocess.TimeoutExpired:
print_formatted_text(
HTML('<ansired>❌ Timeout while pulling runtime image.</ansired>')
)
sys.exit(1)
print_formatted_text('')
print_formatted_text(
@@ -0,0 +1,39 @@
{% if issue_number %}
You are requested to fix issue #{{ issue_number }}: "{{ issue_title }}" in a repository on Bitbucket.
A comment on the issue has been addressed to you.
{% else %}
Your task is to fix the issue: "{{ issue_title }}".
{% endif %}
# Issue Body
{{ issue_body }}
{% if previous_comments %}
# Previous Comments
For reference, here are the previous comments on the issue:
{% for comment in previous_comments %}
- @{{ comment.author }} said:
{{ comment.body }}
{% if not loop.last %}\n\n{% endif %}
{% endfor %}
{% endif %}
# Guidelines
1. Review the task carefully.
2. For all changes to actual application code (e.g. in Python or Javascript), add an appropriate test to the testing directory to make sure that the issue has been fixed
3. Run the tests, and if they pass you are done!
4. You do NOT need to write new tests if there are only changes to documentation or configuration files.
# Final Checklist
Re-read the issue title, body, and comments and make sure that you have successfully implemented all requirements.
Use the Bitbucket token and Bitbucket APIs to:
1. Create a new branch using `openhands/` as a prefix (e.g `openhands/update-readme`)
2. Commit your changes with a clear commit message
3. Push the branch to Bitbucket
4. Create a pull request that:
- Mentions that it "fixes" or "resolves" the issue number
- Has a clear description of the changes made
@@ -0,0 +1,5 @@
{% if issue_comment %}
{{ issue_comment }}
{% else %}
Please fix issue number #{{ issue_number }}.
{% endif %}
@@ -0,0 +1,38 @@
You are checked out to branch {{ branch_name }}, which has an open PR #{{ pr_number }}: "{{ pr_title }}" on Bitbucket.
A comment on the PR has been addressed to you.
# PR Description
{{ pr_body }}
{% if comments %}
# Previous Comments
You may find these other comments relevant:
{% for comment in comments %}
- @{{ comment.author }} said at {{ comment.created_at }}:
{{ comment.body }}
{% if not loop.last %}\n\n{% endif %}
{% endfor %}
{% endif %}
{% if file_location %}
# Comment location
The comment is in the file `{{ file_location }}` on line #{{ line_number }}
{% endif %}.
# Steps to Handle the Comment
## Understand the PR Context
Use the Bitbucket token and Bitbucket API to:
1. Retrieve the diff against the main branch to understand the changes
2. Fetch the PR body and any linked issues for context
## Process the Comment
If it's a question:
1. Answer the question asked
2. DO NOT leave any comments on the PR
If it requests a code update:
1. Modify the code accordingly in the current branch
2. Commit your changes with a clear commit message
3. Push the changes to Bitbucket to update the PR
4. DO NOT leave any comments on the PR
@@ -0,0 +1 @@
{{ pr_comment }}
+1 -1
View File
@@ -59,7 +59,7 @@ def apply_patch(repo_dir: str, patch: str) -> None:
continue
# Handle file rename
if old_path and new_path and 'rename from' in patch:
if old_path and new_path and 'rename from' in diff.text:
# Create parent directory of new path
os.makedirs(os.path.dirname(new_path), exist_ok=True)
try:
+1 -1
View File
@@ -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.all-hands.dev/all-hands-ai/runtime:0.58-nikolaik"
runtime_container_image = "docker.all-hands.dev/all-hands-ai/runtime:0.59-nikolaik"
```
#### Additional Kubernetes Options
@@ -15,6 +15,7 @@ class ConversationTrigger(Enum):
JIRA = 'jira'
JIRA_DC = 'jira_dc'
LINEAR = 'linear'
BITBUCKET = 'bitbucket'
@dataclass
+1 -1
View File
@@ -6,7 +6,7 @@ requires = [
[tool.poetry]
name = "openhands-ai"
version = "0.58.0"
version = "0.59.0"
description = "OpenHands: Code Less, Make More"
authors = [ "OpenHands" ]
license = "MIT"