Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions .github/scripts/generate_release_notes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
#!/usr/bin/env python3
"""Generate a markdown changelog section for the commits since the previous tag.

Usage: generate_release_notes.py <owner/repo> <prev_tag> <next_version>

Reads `git log <prev_tag>..HEAD` and groups Conventional Commit subjects into
sections (same section layout the repo's CHANGELOG.md has always used). The
Release workflow prepends the output to CHANGELOG.md and uses it as the GitHub
Release notes.
"""

from __future__ import annotations

import re
import sys
import subprocess
from datetime import date

SECTIONS = [
("feat", "Features"),
("fix", "Bug Fixes"),
("perf", "Performance Improvements"),
("revert", "Reverts"),
("chore", "Chores"),
("docs", "Documentation"),
("style", "Styles"),
("refactor", "Refactors"),
("build", "Build System"),
("other", "Other Changes"),
]
SECTION_KEYS = {key for key, _ in SECTIONS}
HIDDEN = {"test", "ci", "release"}
CONVENTIONAL = re.compile(r"^(?P<type>[a-z]+)(?:\((?P<scope>[^)]*)\))?!?:\s*(?P<desc>.+)$")


def main() -> None:
repo, prev_tag, next_version = sys.argv[1:4]
log = subprocess.run(
["git", "log", "--no-merges", "--pretty=format:%h\t%H\t%s", f"{prev_tag}..HEAD"],
capture_output=True,
text=True,
check=True,
).stdout

buckets: dict[str, list[str]] = {}
for line in log.splitlines():
if not line.strip():
continue
short, full, subject = line.split("\t", 2)
match = CONVENTIONAL.match(subject)
if match:
kind = match.group("type")
if kind in HIDDEN:
continue
if kind not in SECTION_KEYS:
kind = "other"
scope, desc = match.group("scope"), match.group("desc")
text = f"**{scope}:** {desc}" if scope else desc
else:
kind, text = "other", subject
entry = f"* {text} ([{short}](https://github.com/{repo}/commit/{full}))"
buckets.setdefault(kind, []).append(entry)

out = [
f"## {next_version} ({date.today().isoformat()})",
"",
f"Full Changelog: [{prev_tag}...v{next_version}](https://github.com/{repo}/compare/{prev_tag}...v{next_version})",
]
for kind, title in SECTIONS:
entries = buckets.get(kind, [])
if entries:
out += ["", f"### {title}", ""] + entries
sys.stdout.write("\n".join(out) + "\n")


if __name__ == "__main__":
main()
42 changes: 4 additions & 38 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,14 @@ name: CI
on:
push:
branches:
- '**'
- '!integrated/**'
- '!stl-preview-head/**'
- '!stl-preview-base/**'
- '!generated'
- '!codegen/**'
- 'codegen/stl/**'
- main
pull_request:
branches-ignore:
- 'stl-preview-head/**'
- 'stl-preview-base/**'

jobs:
lint:
timeout-minutes: 10
name: lint
runs-on: ${{ github.repository == 'stainless-sdks/ade-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

Expand All @@ -38,13 +28,9 @@ jobs:
run: ./scripts/lint

build:
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
timeout-minutes: 10
name: build
permissions:
contents: read
id-token: write
runs-on: ${{ github.repository == 'stainless-sdks/ade-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

Expand All @@ -62,30 +48,10 @@ jobs:
- name: Run build
run: rye build

- name: Get GitHub OIDC Token
if: |-
github.repository == 'stainless-sdks/ade-python' &&
!startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
uses: actions/github-script@v8
with:
script: core.setOutput('github_token', await core.getIDToken());

- name: Upload tarball
if: |-
github.repository == 'stainless-sdks/ade-python' &&
!startsWith(github.ref, 'refs/heads/stl/')
env:
URL: https://pkg.stainless.com/s
AUTH: ${{ steps.github-oidc.outputs.github_token }}
SHA: ${{ github.sha }}
run: ./scripts/utils/upload-artifact.sh

test:
timeout-minutes: 10
name: test
runs-on: ${{ github.repository == 'stainless-sdks/ade-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6

Expand Down
5 changes: 1 addition & 4 deletions .github/workflows/release-doctor.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
name: Release Doctor
on:
pull_request:
branches:
- main
workflow_dispatch:

jobs:
release_doctor:
name: release doctor
runs-on: ubuntu-latest
if: github.repository == 'landing-ai/ade-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')
if: github.repository == 'landing-ai/ade-python'

steps:
- uses: actions/checkout@v6
Expand Down
122 changes: 122 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Manual, dispatch-only release automation (replaces the Stainless-run
# release-please after the platform sunset on 2026-09-01).
#
# A maintainer runs this workflow (Actions -> Release -> Run workflow) and
# picks the bump: patch / minor / major. The workflow then, in one shot:
# 1. computes the next version from the latest git tag,
# 2. stamps it into pyproject.toml and src/landingai_ade/_version.py,
# 3. prepends a changelog section (grouped by Conventional Commit prefixes)
# to CHANGELOG.md,
# 4. builds and tests the stamped tree — the release aborts here, before
# any commit or tag exists, if anything is red,
# 5. lands that as a "release: x.y.z" commit directly on main,
# 6. tags it and creates the GitHub Release, which triggers
# .github/workflows/publish-pypi.yml.
#
# No release PR, no second confirmation: dispatching the workflow IS the
# release decision. Ordinary PR merges never trigger any of this.
#
# RELEASE_TOKEN requirements:
# - a fine-grained PAT (or GitHub App installation token) with
# Contents: write on this repository;
# - its owner must be able to bypass the main-branch ruleset (the ruleset
# requires PRs; this repo's ruleset grants "always" bypass to
Comment thread
MingruiZhang marked this conversation as resolved.
# organization admins). Otherwise the direct push in step 4 is rejected.
# - The default GITHUB_TOKEN cannot be used: releases it creates do not
# trigger other workflows, so publishing would silently never run.
name: Release

on:
workflow_dispatch:
inputs:
bump:
description: 'Version bump for this release'
type: choice
required: true
options:
- patch
- minor
- major

# Only one release can run at a time; a second dispatch queues rather than
# racing the version computation and the push to main.
concurrency:
group: release
cancel-in-progress: false

jobs:
release:
name: release
runs-on: ubuntu-latest
if: github.repository == 'landing-ai/ade-python' && github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0 # full history: needed for the previous tag + changelog range
token: ${{ secrets.RELEASE_TOKEN }}
Comment thread
MingruiZhang marked this conversation as resolved.

- name: Compute next version
id: version
env:
BUMP: ${{ inputs.bump }}
run: |
prev_tag="$(git describe --tags --abbrev=0)"
current="${prev_tag#v}"
IFS='.' read -r major minor patch <<< "$current"
case "$BUMP" in
major) next="$((major + 1)).0.0" ;;
minor) next="${major}.$((minor + 1)).0" ;;
patch) next="${major}.${minor}.$((patch + 1))" ;;
esac
echo "bumping $current -> $next ($BUMP)"
{
echo "prev_tag=$prev_tag"
echo "version=$next"
} >> "$GITHUB_OUTPUT"

- name: Stamp version
env:
NEXT: ${{ steps.version.outputs.version }}
run: |
sed -i -E "s/^version = \".*\"/version = \"$NEXT\"/" pyproject.toml
sed -i -E "s/__version__ = \".*\"/__version__ = \"$NEXT\"/" src/landingai_ade/_version.py
git diff --stat

- name: Update changelog
env:
PREV_TAG: ${{ steps.version.outputs.prev_tag }}
NEXT: ${{ steps.version.outputs.version }}
run: |
python3 .github/scripts/generate_release_notes.py \
"${{ github.repository }}" "$PREV_TAG" "$NEXT" > /tmp/release-notes.md
{ head -n 2 CHANGELOG.md; cat /tmp/release-notes.md; echo; tail -n +3 CHANGELOG.md; } > /tmp/changelog.md
mv /tmp/changelog.md CHANGELOG.md

- name: Install Rye
run: |
curl -sSf https://rye.astral.sh/get | bash
echo "$HOME/.rye/shims" >> $GITHUB_PATH
env:
RYE_VERSION: '0.44.0'
RYE_INSTALL_OPTION: '--yes'

- name: Build and test the stamped tree
run: |
./scripts/bootstrap
rye build
./scripts/test

- name: Commit, tag, and create the GitHub Release
env:
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
NEXT: ${{ steps.version.outputs.version }}
Comment thread
MingruiZhang marked this conversation as resolved.
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add pyproject.toml src/landingai_ade/_version.py CHANGELOG.md
git commit -m "release: $NEXT"
git push origin HEAD:main
gh release create "v$NEXT" \
--target "$(git rev-parse HEAD)" \
--title "v$NEXT" \
--notes-file /tmp/release-notes.md
3 changes: 0 additions & 3 deletions .release-please-manifest.json

This file was deleted.

4 changes: 0 additions & 4 deletions .stats.yml

This file was deleted.

15 changes: 11 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,20 @@ $ pip install -r requirements-dev.lock

## Modifying/Adding code

Most of the SDK is generated code. Modifications to code will be persisted between generations, but may
result in merge conflicts between manual patches and changes from the generator. The generator will never
modify the contents of the `src/landingai_ade/lib/` and `examples/` directories.
This SDK is fully owned and hand-maintained by LandingAI; it is no longer regenerated by Stainless.
All code in the repository can be edited directly, like any other codebase.

Please use [Conventional Commits](https://www.conventionalcommits.org/) for commit messages and PR
titles (`feat:`, `fix:`, `chore:`, …) — the release changelog is grouped by these prefixes.

Releases are cut manually: a maintainer runs the **Release** workflow (Actions → Release → Run
workflow) and chooses the version bump (patch / minor / major). The workflow lands a
`release: x.y.z` commit on `main` (version stamping + changelog), tags it, and creates the GitHub
Release — which triggers publishing. Ordinary PR merges never trigger a release.

## Adding and running examples

All files in the `examples/` directory are not modified by the generator and can be freely edited or added to.
Files in the `examples/` directory can be freely edited or added to.

```py
# add an example to examples/<your-example>.py
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
</div>


A Python library for interacting with the **LandingAI Agentic Document Extraction REST API**, designed for flexibility, reliability, clarity, and performance. Built for Python 3.9+ and generated with [Stainless](https://www.stainless.com/).
A Python library for interacting with the **LandingAI Agentic Document Extraction REST API**, designed for flexibility, reliability, clarity, and performance. Built for Python 3.9+.


## ✨ Features
Expand All @@ -40,7 +40,6 @@ A Python library for interacting with the **LandingAI Agentic Document Extractio
Use the LandingAI ADE MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.

[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=landingai-ade-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsImxhbmRpbmdhaS1hZGUtbWNwIl0sImVudiI6eyJWSVNJT05fQUdFTlRfQVBJX0tFWSI6Ik15IEFwaWtleSJ9fQ)
[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22landingai-ade-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22landingai-ade-mcp%22%5D%2C%22env%22%3A%7B%22VISION_AGENT_API_KEY%22%3A%22My%20Apikey%22%7D%7D)

> Note: You may need to set environment variables in your MCP client.

Expand Down
15 changes: 6 additions & 9 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,22 @@

## Reporting Security Issues

This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken.
This SDK is maintained by [LandingAI](https://landing.ai/).

To report a security issue, please contact the Stainless team at [email protected].
To report a security issue, please use GitHub's private vulnerability reporting on this repository
("Security" → "Report a vulnerability"), or contact us at [email protected].

## Responsible Disclosure

We appreciate the efforts of security researchers and individuals who help us maintain the security of
SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible
our SDKs. If you believe you have found a security vulnerability, please adhere to responsible
disclosure practices by allowing us a reasonable amount of time to investigate and address the issue
before making any information public.

## Reporting Non-SDK Related Security Issues

If you encounter security issues that are not directly related to SDKs but pertain to the services
or products provided by LandingAI ADE, please follow the respective company's security reporting guidelines.

### LandingAI ADE Terms and Policies

Please contact [email protected] for any questions or concerns regarding the security of our services.
If you encounter security issues that are not directly related to this SDK but pertain to the services
or products provided by LandingAI, please contact [email protected].

---

Expand Down
Loading