Skip to content

Commit 8fed9d1

Browse files
authored
Merge branch 'main' into openhands/issue-2788-agent-settings-migrations
2 parents 3890fc4 + cce8f10 commit 8fed9d1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+991
-468
lines changed

.github/workflows/pypi-release.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ on:
1010

1111
jobs:
1212
publish:
13+
# Skip PyPI publishing for pre-releases (e.g., release candidates).
14+
# Pre-releases can still be created on GitHub for testing without
15+
# pushing packages to PyPI. Manual workflow_dispatch always runs.
16+
if: >
17+
github.event_name == 'workflow_dispatch' ||
18+
!github.event.release.prerelease
1319
runs-on: ubuntu-24.04
1420
outputs:
1521
version: ${{ steps.extract_version.outputs.version }}

.github/workflows/server.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,9 @@ jobs:
210210
ARCH: ${{ matrix.arch }}
211211
TARGET: binary
212212
PLATFORM: ${{ matrix.platform }}
213-
# Use PR head SHA for pull requests to match the image tag expected by run-examples.yml
214-
GITHUB_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
213+
# Use SDK_SHA for PR head SHA - GITHUB_SHA is a built-in that gets overwritten by checkout
214+
# build.py checks SDK_SHA before GITHUB_SHA (see _git_info priority order)
215+
SDK_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
215216
GITHUB_REF: ${{ github.ref }}
216217
CI: 'true'
217218

@@ -254,7 +255,8 @@ jobs:
254255
echo "tags=$TAGS" >> $GITHUB_OUTPUT
255256
256257
# Extract short SHA for consolidation
257-
SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7)
258+
# Use SDK_SHA env var (set above to PR head SHA for PRs)
259+
SHORT_SHA=$(echo $SDK_SHA | cut -c1-7)
258260
echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT
259261
260262
# Extract versioned tags CSV for consolidation

examples/01_standalone_sdk/43_mixed_marketplace_skills/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
import sys
3838
from pathlib import Path
3939

40-
from openhands.sdk.plugin import Marketplace
40+
from openhands.sdk.marketplace import Marketplace
4141
from openhands.sdk.skills import (
4242
install_skills_from_marketplace,
4343
list_installed_skills,

examples/05_skills_and_plugins/01_loading_agentskills/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from pydantic import SecretStr
2828

2929
from openhands.sdk import LLM, Agent, AgentContext, Conversation
30-
from openhands.sdk.context.skills import (
30+
from openhands.sdk.skills import (
3131
discover_skill_resources,
3232
load_skills_from_dir,
3333
)

openhands-agent-server/openhands/agent_server/docker/Dockerfile

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,32 @@ ARG PORT=8000
1313
# Builder (source mode)
1414
# We copy source + build a venv here for local dev and debugging.
1515
#
16-
# NOTE: We use the base image's system Python (--python-preference only-system)
17-
# instead of uv-managed python-build-standalone. The python-build-standalone
18-
# builds ship libpython with an executable stack (PT_GNU_STACK PF_X).
19-
# Docker containers running under seccomp restrictions (e.g. GitHub Actions
20-
# Docker-in-Docker) reject dlopen() on such libraries with:
21-
# "cannot enable executable stack as shared object requires: Invalid argument"
22-
# Debian's CPython packages do not have this issue.
16+
# SELF-CONTAINED /agent-server CONTRACT:
17+
# uv installs python-build-standalone into /agent-server/uv-managed-python and
18+
# creates .venv against it. Both live under /agent-server, so downstream
19+
# consumers can COPY /agent-server onto any base image and the venv works.
20+
#
21+
# uv >= 0.11.5 pulls python-build-standalone >= 20260408, which ships
22+
# libpython without PT_GNU_STACK PF_X (executable stack). Earlier releases
23+
# had this flag set due to LLVM/BOLT bugs, causing glibc >= 2.41 and
24+
# DinD/sysbox/seccomp to reject dlopen() with "cannot enable executable
25+
# stack". No sanitizer or workaround is needed on fixed releases.
26+
# See OpenHands/software-agent-sdk#2761.
2327
####################################################################################
2428
FROM python:3.13-bookworm AS builder
2529
ARG USERNAME UID GID
2630
ENV UV_PROJECT_ENVIRONMENT=/agent-server/.venv
31+
ENV UV_PYTHON_INSTALL_DIR=/agent-server/uv-managed-python
2732

28-
COPY --from=ghcr.io/astral-sh/uv /uv /uvx /bin/
33+
# uv 0.11.5+ embeds python-build-standalone 20260408 metadata, which is the
34+
# first release with the PT_GNU_STACK fix. Pin to 0.11.6 (latest at time of
35+
# writing) rather than :latest so builds are reproducible.
36+
COPY --from=ghcr.io/astral-sh/uv:0.11.6 /uv /uvx /bin/
2937

3038
RUN groupadd -g ${GID} ${USERNAME} \
31-
&& useradd -m -u ${UID} -g ${GID} -s /usr/sbin/nologin ${USERNAME}
39+
&& useradd -m -u ${UID} -g ${GID} -s /usr/sbin/nologin ${USERNAME} \
40+
&& mkdir -p /agent-server/uv-managed-python \
41+
&& chown -R ${USERNAME}:${USERNAME} /agent-server
3242
USER ${USERNAME}
3343
WORKDIR /agent-server
3444
# Cache-friendly: lockfiles first
@@ -38,7 +48,10 @@ COPY --chown=${USERNAME}:${USERNAME} openhands-tools ./openhands-tools
3848
COPY --chown=${USERNAME}:${USERNAME} openhands-workspace ./openhands-workspace
3949
COPY --chown=${USERNAME}:${USERNAME} openhands-agent-server ./openhands-agent-server
4050
RUN --mount=type=cache,target=/home/${USERNAME}/.cache,uid=${UID},gid=${GID} \
41-
uv venv --python-preference only-system .venv && uv sync --frozen --no-editable --extra boto3
51+
uv python install 3.13 && \
52+
uv venv --python-preference only-managed --python 3.13 .venv && \
53+
uv sync --frozen --no-editable --managed-python --extra boto3 && \
54+
readlink -f .venv/bin/python | grep -q '^/agent-server/uv-managed-python/'
4255

4356
####################################################################################
4457
# Binary Builder (binary mode)
@@ -135,7 +148,7 @@ RUN mkdir -p /etc/claude-code && \
135148

136149
# NOTE: we should NOT include UV_PROJECT_ENVIRONMENT here,
137150
# since the agent might use it to perform other work (e.g. tools that use Python)
138-
COPY --from=ghcr.io/astral-sh/uv /uv /uvx /bin/
151+
COPY --from=ghcr.io/astral-sh/uv:0.11.6 /uv /uvx /bin/
139152

140153
USER ${USERNAME}
141154
WORKDIR /

openhands-agent-server/openhands/agent_server/skills_router.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
load_all_skills,
1515
sync_public_skills,
1616
)
17-
from openhands.sdk.context.skills.skill import DEFAULT_MARKETPLACE_PATH
17+
from openhands.sdk.skills.skill import DEFAULT_MARKETPLACE_PATH
1818

1919

2020
skills_router = APIRouter(prefix="/skills", tags=["Skills"])

openhands-agent-server/openhands/agent_server/skills_service.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,21 @@
2020
from dataclasses import dataclass
2121
from pathlib import Path
2222

23-
from openhands.sdk.context.skills import (
23+
from openhands.sdk.logger import get_logger
24+
from openhands.sdk.skills import (
2425
Skill,
2526
load_available_skills,
2627
)
27-
from openhands.sdk.context.skills.skill import (
28+
from openhands.sdk.skills.skill import (
2829
DEFAULT_MARKETPLACE_PATH,
2930
PUBLIC_SKILLS_BRANCH,
3031
PUBLIC_SKILLS_REPO,
3132
load_skills_from_dir,
3233
)
33-
from openhands.sdk.context.skills.utils import (
34+
from openhands.sdk.skills.utils import (
3435
get_skills_cache_dir,
3536
update_skills_repository,
3637
)
37-
from openhands.sdk.logger import get_logger
3838
from openhands.sdk.utils import sanitized_env
3939

4040

openhands-sdk/openhands/sdk/__init__.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@
55
AgentBase,
66
)
77
from openhands.sdk.banner import _print_banner
8-
from openhands.sdk.context import (
9-
AgentContext,
10-
load_project_skills,
11-
load_skills_from_dir,
12-
load_user_skills,
13-
)
8+
from openhands.sdk.context import AgentContext
149
from openhands.sdk.context.condenser import (
1510
LLMSummarizingCondenser,
1611
)
@@ -66,6 +61,11 @@
6661
SettingsSectionMetadata,
6762
field_meta,
6863
)
64+
from openhands.sdk.skills import (
65+
load_project_skills,
66+
load_skills_from_dir,
67+
load_user_skills,
68+
)
6969
from openhands.sdk.subagent import (
7070
agent_definition_to_factory,
7171
load_agents_from_dir,

openhands-sdk/openhands/sdk/context/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from openhands.sdk.context.agent_context import AgentContext
22
from openhands.sdk.context.prompts import render_template
3-
from openhands.sdk.context.skills import (
3+
4+
# Import from canonical location (openhands.sdk.skills)
5+
from openhands.sdk.skills import (
46
BaseTrigger,
57
KeywordTrigger,
68
Skill,

openhands-sdk/openhands/sdk/context/agent_context.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@
77
from pydantic import BaseModel, Field, field_validator, model_validator
88

99
from openhands.sdk.context.prompts import render_template
10-
from openhands.sdk.context.skills import (
10+
from openhands.sdk.llm import Message, TextContent
11+
from openhands.sdk.llm.utils.model_prompt_spec import get_model_prompt_spec
12+
from openhands.sdk.logger import get_logger
13+
from openhands.sdk.secret import SecretSource, SecretValue
14+
from openhands.sdk.skills import (
1115
Skill,
1216
SkillKnowledge,
1317
load_available_skills,
1418
to_prompt,
1519
)
16-
from openhands.sdk.context.skills.skill import DEFAULT_MARKETPLACE_PATH
17-
from openhands.sdk.llm import Message, TextContent
18-
from openhands.sdk.llm.utils.model_prompt_spec import get_model_prompt_spec
19-
from openhands.sdk.logger import get_logger
20-
from openhands.sdk.secret import SecretSource, SecretValue
20+
from openhands.sdk.skills.skill import DEFAULT_MARKETPLACE_PATH
2121

2222

2323
logger = get_logger(__name__)

0 commit comments

Comments
 (0)