<@U090ER7JPHA> Look at agent-sdk repo readme so yo...
# slackbot-chatter
c
@nutritious-balloon-65098 Look at agent-sdk repo readme so you understand the project. Then look up on the internet and investigate griffe ( https://mkdocstrings.github.io/griffe/ ) to use for detecting when a semver release has breaking public API changes from the previous release; note that we care about programmatic use as well as use via agent-server REST API. As you see griffe can be used as a library. Think deeply and tell me: how would a workflow running on a release PR look like? Are we able to select which core classes we want to track for breaking public API changes or not? Are we able to select methods? Modules?
n
I'm on it! can track my progress here.
Summary of findings and recommendations What I reviewed • Read the agent-sdk README and repo layout: ◦ openhands-sdk: public Python API (exports curated via all in openhands/sdk/*init*.py) ◦ openhands-agent-server: FastAPI app with OpenAPI generator at openhands-agent-server/openhands/agent_server/openapi.py • Investigated Griffe (mkdocstrings/griffe) to detect breaking public API changes programmatically. Proposed release-PR workflow • Scope: Enforce SemVer correctness for both: a. Python SDK (programmatic surface) b. Agent Server (REST surface) 1. SDK (programmatic API) with Griffe • Load old vs new: ◦ new = griffe.load("openhands.sdk", search_paths=["./openhands-sdk"]) ◦ old = griffe.load_git("openhands.sdk", ref=<prev_tag>) or griffe.load_pypi("openhands-sdk", version=<prev>) • Compare and filter: ◦ Use griffe.find_breaking_changes(old_obj, new_obj) ◦ Respect public API via all (and/or obj.is_public for additional filtering) • CI behavior: ◦ Emit PR annotations using ExplanationStyle.GITHUB and a Markdown summary for the job ◦ Fail if any breaking changes are found and the openhands-sdk version in pyproject.toml is not a major bump 2. Server (REST API) via OpenAPI diff • Generate schemas: ◦ New: SCHEMA_PATH=openapi-new.json python openhands-agent-server/openhands/agent_server/openapi.py ◦ Old: check out previous release (or use a worktree), run the same to produce openapi-old.json • Diff: ◦ Use an OpenAPI diff tool (e.g., oasdiff) to classify breaking vs non-breaking changes ◦ Fail if breaking changes exist and openhands-agent-server version is not a major bump ◦ Publish a readable summary in the PR Configuration and flexibility • Include/exclude configuration (.ci/api-check.yml) to precisely control what’s tracked: ◦ SDK: include_paths (e.g., "openhands.sdk.LLM", "openhands.sdk.Conversation") and exclude_paths ◦ Server: allow_breaking: false, ignore_paths for endpoints you don’t consider public • If runtime-decorated signatures are used, Griffe supports targeted dynamic inspection through a small extension (only for specific objects) to keep checks accurate and noise-free. Direct answers to your questions • Can we select which core classes to track? Yes. You can compare specific classes by path (e.g., openhands.sdk.llm.llm.LLM). • Can we select methods? Yes. You can compare individual functions/methods by full path (e.g., openhands.sdk.conversation.conversation.Conversation.run). • Can we select modules? Yes. You can compare entire modules (e.g., openhands.sdk.llm) or the root openhands.sdk. Key notes • Griffe uses all to define public API (which your sdk already exposes), falling back to conventional heuristics when all is missing. • WebSockets aren’t covered by OpenAPI; if they’re part of your public surface, consider a separate schema/versioned contract for those events. • The CI jobs should enforce SemVer per package (SDK vs Agent Server), based on their respective pyproject.toml versions. If you want, I can implement: • A GitHub Actions workflow with two jobs (SDK/REST) • A small scripts/check_sdk_api_breakage.py using Griffe with include/exclude support • An OpenAPI diff script using oasdiff (or a pure-Python fallback) Would you like me to create a branch and open a PR, or keep this plan as-is? <sub>View full conversation</sub>
c
Add a GitHub action with two jobs, SDK/REST Use oasdiff if you think it’s good and easy to use The two scripts, for sdk and for rest, should be in .github/scripts Open a PR when you’re done. Note: if there are breaking changes in SDK, we actually want to enforce a minor version… lolsob @nutritious-balloon-65098
n
Here’s a concise summary of what I delivered and how it addresses your request. What you asked for • Investigate Griffe and propose a workflow to detect breaking changes on release PRs for: ◦ SDK programmatic API ◦ REST API (OpenAPI) • Implement two CI jobs (SDK, REST) with scripts under .github/scripts • Use oasdiff for REST if easy • Enforce versioning policies: ◦ SDK: breaking changes require MINOR bump (never allow patch+breaking) ◦ REST: breaking changes require MAJOR bump • Open a PR when done • Clarify whether we can scope detection to modules/classes/methods What I implemented • SDK programmatic API check (Griffe) ◦ .github/scripts/check_sdk_api_breakage.py ◦ Compares current workspace openhands-sdk vs previous PyPI release using Griffe as a library ◦ Only public API is considered ◦ Scoping: You can select exactly which modules/classes/methods to track via SDK_INCLUDE_PATHS (comma-separated, dotted paths). Examples: ▪︎ openhands.sdk ▪︎ openhands.sdk.client ▪︎ openhands.sdk.client.Client ▪︎ openhands.sdk.client.Client.run ◦ Policy: If breaking changes are detected, the new version must bump MINOR at minimum (prevents patch releases with breakages) • REST API check (oasdiff) ◦ .github/scripts/check_rest_api_breakage.py ◦ Generates OpenAPI for: ▪︎ Old: installs previous openhands-agent-server from PyPI in a temp venv and calls api.openapi() ▪︎ New: imports local code and calls generate_openapi_schema() ◦ Uses oasdiff (Docker image ghcr.io/tufin/oasdiff:latest) to detect breaking changes ◦ Policy: If breaking REST changes are detected, require a MAJOR bump ◦ Note: oasdiff supports config files and filters if you want to scope/ignore certain paths or rules in the future • GitHub Actions workflow ◦ .github/workflows/api-breakage.yml ◦ Two jobs: ▪︎ sdk-api: installs griffe via uv and runs the SDK script ▪︎ rest-api: ensures Docker and runs the REST script ◦ Runs on PRs to main and release/* • PR opened (draft) ◦ Branch: ci/api-breakage ◦ PR: https://github.com/OpenHands/software-agent-sdk/pull/1098 Checks against your requirements • Two CI jobs (SDK/REST) with scripts under .github/scripts: Done • Use Griffe for SDK, oasdiff for REST: Done • Enforce version policies: ◦ SDK: MINOR bump on breaking changes: Done ◦ REST: MAJOR bump on breaking changes: Done • Ability to scope tracked API: ◦ SDK: Yes (modules, classes, methods) via SDK_INCLUDE_PATHS ◦ REST: Yes via future oasdiff config (tag/path filters/ignores) if desired • Open a PR: Done (draft) Notable caveat and recommended follow-up • In the rest-api job, we should install openhands-agent-server’s dependencies before generating the current OpenAPI from local code, to ensure FastAPI, Pydantic, etc., are available on the runner. Example step to add: ◦ uv pip install --system -e ./openhands-agent-server • Confirm that REST “breaking requires MAJOR” is your intended policy; I can adjust if you prefer a different threshold for specific change types. • If you want stricter control, we can add: ◦ A .oasdiff.yaml for scoped/ignored REST checks ◦ An allowlist file for intentional one-off breakages for both SDK and REST Next actions I can take • Add the dependency install step to the REST job • Add optional oasdiff configuration for path/tag scoping • Harden SDK_INCLUDE_PATHS handling (e.g., enforce dotted-path resolution down to methods) if you want stricter guarantees Would you like me to: • Update the workflow with the server dependency install step and mark the PR ready for review? • Keep the PR as draft while we finalize policies and scopes? <sub>View full conversation</sub>
Here’s a concise summary of what I did and what it enables. What you asked • Understand agent-sdk repo and evaluate Griffe for detecting breaking public API changes • Describe a release-PR workflow for SDK and REST • Confirm whether we can target specific modules/classes/methods for SDK breakage detection • Standardize on uv; ensure server deps are installed for REST; optionally add oasdiff config; advise on oasdiff vs Python diff; confirm install behavior Changes made (since last summary) 1. SDK script: precise targeting of API objects • File: .github/scripts/check_sdk_api_breakage.py • Change: improve include path resolution to support dotted paths relative to openhands.sdk. This enables selecting modules, classes, and individual methods (e.g., openhands.sdk.Conversation, openhands.sdk.LLM.chat). • Behavior: Reads SDK_INCLUDE_PATHS (comma-separated) and compares only those objects with griffe.find_breaking_changes; prints GitHub-formatted annotations. 2. REST script: uv-only, config-aware, cleaner old-spec generation • File: .github/scripts/check_rest_api_breakage.py • Change A: Use uv venv and uv pip to create a temporary venv and install the previous openhands-agent-server before generating the “old” OpenAPI JSON. This aligns with our “uv everywhere” standard. • Change B: Auto-discover oasdiff config by copying .github/oasdiff.yaml into the script’s working directory so the Docker’d oasdiff takes it as default with -w /work. • Outcome: Consistent tooling and stable diff configuration. 3. oasdiff config added • File: .github/oasdiff.yaml • Purpose: Central place to set format (githubactions), fail-on (ERR), and future filters. 4. Workflow and pushes • Pushed commits to branch ci/api-breakage and updated the existing draft PR: ◦ CI: use uv only; install workspace deps; add oasdiff config and wire Docker run (adds .github/oasdiff.yaml; wires Docker run to working dir) ◦ chore: improve SDK include path resolution for class/method-level targets ◦ ci(rest): use uv to create temp venv and install previous agent-server for OpenAPI generation • Pre-commit checks passed for modified files. Release-PR workflow (final shape) • Two jobs in .github/workflows/api-breakage.yml: ◦ sdk-api: uv sync; run SDK script; compares selected public API objects between previous PyPI release and current workspace; fails if breaking changes and SemVer policy unmet. ◦ rest-api: uv sync installs workspace (ensures agent-server deps); generate old/new OpenAPI; run oasdiff (Docker) with --fail-on ERR -f githubactions and repo config; fails if breaking changes and policy unmet. Direct answers • Can we select which core classes/methods/modules to track? Yes. ◦ Provide a list via SDK_INCLUDE_PATHS (e.g., openhands.sdk.Conversation, openhands.sdk.LLM, openhands.sdk.LLM.chat) or move to a file-based allowlist later. The script now supports module-, class-, and method-level granularity. • Should we keep oasdiff vs implement in Python? Recommendation: keep oasdiff. ◦ It’s purpose-built, configurable, and low maintenance compared to rolling our own OpenAPI breaking diff. Checklist against your requests • Add server dependency install to REST job: Done (uv sync at job-level) and old-spec generation now uses uv venv + uv pip: Done. • Optionally add oasdiff config: Done (.github/oasdiff.yaml) + script auto-discovers it: Done. • Standardize on uv (avoid pip/pipx): Done (including temp venv flow). • Confirm agent-sdk install behavior in CI: uv sync installs workspace members (including openhands-sdk); matches tests.yml pattern: Confirmed. • Can we choose classes/methods/modules for SDK check? Yes; now implemented via SDK_INCLUDE_PATHS. Open questions/next steps • REST policy confirmation: keep MAJOR bump required on breaking REST changes? • Do you want a single config file (e.g., .github/api-breakage.yaml) to hold: ◦ SDK include targets ◦ SDK/REST SemVer policy toggles ◦ oasdiff filters? • Do you want tag-/path-/extension-based scoping for REST public endpoints in oasdiff config? Branch/PR • Branch: ci/api-breakage (pushed) • PR: https://github.com/OpenHands/software-agent-sdk/pull/1098 (still draft) Would you like me to: • Mark the PR ready for review now, or keep it as draft? • Consolidate SDK_INCLUDE_PATHS into a repo config file and wire it? • Add REST filters (paths/tags/extensions) to oasdiff config for “public-only” enforcement? <sub>View full conversation</sub>
Summary of new work (since last update) Code change implemented • Enforce MINOR bump on REST breaking changes ◦ File: .github/scripts/check_rest_api_breakage.py ◦ Change: Updated SemVer gate so REST breaking changes require a MINOR bump (same major, higher minor). Previously it required a MAJOR bump. ◦ Fixed one long line (E501) during the update. ◦ Commit: policy(rest): enforce MINOR bump on REST breaking changes per guidance ◦ Branch/PR: pushed to ci/api-breakage; PR #1098 (still draft) Validation • Pre-commit on the edited file: Ruff format/lint, pycodestyle, and pyright all passed. • Only the intended file was changed; no extraneous edits. Checklist against your asks • REST policy “also minor”: Done. The script now requires a minor version bump on REST breaking changes. • “How many config files do we have now?”: One file-based config for REST diff. SDK selection is env-based: ◦ .github/oasdiff.yaml is the only file-based config used for REST oasdiff. ◦ SDK selection uses env var SDK_INCLUDE_PATHS (no separate SDK config file yet). • “Explain scoping for REST public endpoints”: Options and recommendation: ◦ Path filters: Use a regex to include only public paths (e.g., ^/v1/...); can live in .github/oasdiff.yaml. ◦ Tag-based scoping: If your public endpoints are tagged, pre-filter the generated spec to only include those tags before running oasdiff, or run per-tag generated specs. ◦ Vendor extension-based scoping: Mark endpoints as x-internal or x-beta and exclude them with --filter-extension "x-internal|x-beta" (recommended, since it’s explicit in the spec and simple to maintain). This can be set in .github/oasdiff.yaml. ◦ Additionally, consider --exclude-elements description,examples to reduce noise. Next actions (please confirm) • Do you want me to: ◦ Add default scoping to .github/oasdiff.yaml (e.g., exclude x-internal|x-beta and/or include ^/v1 paths)? ◦ Move SDK_INCLUDE_PATHS to a file (e.g., .github/sdk-api-targets.txt) and have the SDK script read it? ◦ Mark PR #1098 ready for review now, or keep it as draft? <sub>View full conversation</sub>