Skip to content
Draft
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
96 changes: 96 additions & 0 deletions .github/workflows/_sdk-acceptance.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: SDK acceptance

on:
workflow_call:

permissions:
contents: read

jobs:
contract:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Test contract workflow helpers
run: python3 -m unittest discover -s tests -v

- name: Verify contract provenance and generator pin
run: python3 -m scripts.check_contract_provenance

- name: Check OpenAPI backward compatibility
env:
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PUSH_BASE_SHA: ${{ github.event.before }}
run: |
set -euo pipefail
BASE_SHA="${PR_BASE_SHA:-${PUSH_BASE_SHA:-}}"
if [ -z "$BASE_SHA" ] || [ "$BASE_SHA" = "0000000000000000000000000000000000000000" ]; then
BASE_SHA="$(git rev-parse HEAD^)"
fi
python3 scripts/check_openapi_compatibility.py \
--base "${BASE_SHA}:sdk/openapi.json"

- name: Regenerate with pinned OpenAPI Generator
run: bash scripts/generate-sdks.sh sdk/openapi.json

- name: Check generated-code freshness
run: bash scripts/check-generated-freshness.sh

- name: Check generated operation coverage
run: python3 scripts/check_operation_coverage.py

- name: Check exact generated Python contract shape
run: |
python3 scripts/check_python_generated_contract.py
python3 scripts/postprocess_python_models.py --check
python3 scripts/generate_python_contract_manifest.py --check

- name: Check generated Python API reference
run: python3 scripts/generate_python_api_reference.py --check

python:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.12", "3.14"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install Python SDK and test dependencies
run: python -m pip install -e 'sdk/python[dev]'
- name: Test generated-client conformance and model policy
run: python -m pytest sdk/python/tests quality/python -q
- name: Build Python distributions
run: python -m build sdk/python

typescript:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: sdk/typescript/package-lock.json
- run: npm ci
working-directory: sdk/typescript
- run: npm run build
working-directory: sdk/typescript

go:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: sdk/go/go.mod
cache-dependency-path: sdk/go/go.sum
- run: go test ./...
working-directory: sdk/go
57 changes: 2 additions & 55 deletions .github/workflows/generate-sdks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,58 +14,5 @@ concurrency:
cancel-in-progress: true

jobs:
contract:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4

- name: Test contract workflow helpers
run: python3 -m unittest discover -s tests -v

- name: Verify contract provenance and generator pin
run: python3 -m scripts.check_contract_provenance

- name: Regenerate with pinned OpenAPI Generator
run: bash scripts/generate-sdks.sh sdk/openapi.json

- name: Check generated-code freshness
run: bash scripts/check-generated-freshness.sh

- name: Check generated operation coverage
run: python3 scripts/check_operation_coverage.py

python:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- run: python -m pip install -r sdk/python/requirements.txt -r sdk/python/test-requirements.txt
- run: python -m pytest sdk/python/test -q

typescript:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: sdk/typescript/package-lock.json
- run: npm ci
working-directory: sdk/typescript
- run: npm run build
working-directory: sdk/typescript

go:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: sdk/go/go.mod
cache-dependency-path: sdk/go/go.sum
- run: go test ./...
working-directory: sdk/go
acceptance:
uses: ./.github/workflows/_sdk-acceptance.yml
100 changes: 72 additions & 28 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,84 @@ name: Publish SDKs

# Publishes the generated SDKs:
# - Python -> PyPI (agentdrive-sdk) via OIDC trusted publishing (no token)
# - TS -> npm (@mnexa-ai/agentdrive-sdk) via NPM_TOKEN secret
# - TS -> npm (@mnexa-ai/agentdrive-sdk) via OIDC trusted publishing
# - Go -> git tag go/vX.Y.Z (consumed with `go get .../go@vX.Y.Z`)
#
# Publishes the version currently baked into the generated package metadata.
# Bump by re-running "Generate SDKs" with SDK_VERSION set, then release.
# Every publish is gated on the release/dispatch version matching sdk/SDK_VERSION
# and every language's package metadata. Existing versions are hard failures.

on:
release:
types: [published]
workflow_dispatch:
inputs:
version:
description: "Version being published (e.g. 0.0.1), used for the Go tag."
description: "Exact SDK version being published (e.g. 0.1.0)."
required: true
default: "0.0.1"
default: "0.1.0"

jobs:
release-policy:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Require an approved main-branch commit
env:
EVENT_NAME: ${{ github.event_name }}
RELEASE_REF: ${{ github.ref }}
RELEASE_SHA: ${{ github.sha }}
run: |
set -euo pipefail
if [ "$EVENT_NAME" = "workflow_dispatch" ] && [ "$RELEASE_REF" != "refs/heads/main" ]; then
echo "Manual SDK publishing is allowed only from refs/heads/main; got $RELEASE_REF." >&2
exit 1
fi
if [ "$EVENT_NAME" = "release" ]; then
git fetch --no-tags origin \
'+refs/heads/main:refs/remotes/origin/main'
if ! git merge-base --is-ancestor "$RELEASE_SHA" refs/remotes/origin/main; then
echo "Release commit $RELEASE_SHA is not contained in origin/main." >&2
exit 1
fi
fi

acceptance:
needs: release-policy
uses: ./.github/workflows/_sdk-acceptance.yml

release-integrity:
needs: acceptance
runs-on: ubuntu-latest
permissions:
contents: read
outputs:
version: ${{ steps.version.outputs.version }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Match publish input to every package version
id: version
env:
REQUESTED_VERSION: ${{ github.event.release.tag_name || github.event.inputs.version }}
run: |
set -euo pipefail
VERSION="$(python3 scripts/check_release_version.py \
--requested "$REQUESTED_VERSION" \
--event "${{ github.event_name }}")"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

pypi:
needs: [acceptance, release-integrity]
runs-on: ubuntu-latest
environment: pypi
permissions:
contents: read
id-token: write # OIDC trusted publishing
steps:
- uses: actions/checkout@v4
Expand All @@ -38,9 +95,9 @@ jobs:
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: sdk/python/dist
skip-existing: true

npm:
needs: [acceptance, release-integrity]
runs-on: ubuntu-latest
permissions:
id-token: write # OIDC trusted publishing (no NPM token)
Expand All @@ -57,25 +114,12 @@ jobs:
- name: Build & publish (OIDC, no token)
working-directory: sdk/typescript
run: |
npm install
npm ci
npm run build
VERSION="$(node -p "require('./package.json').version")"
if npm view "@mnexa-ai/agentdrive-sdk@${VERSION}" version >/dev/null 2>&1; then
echo "npm: @mnexa-ai/agentdrive-sdk@${VERSION} already published — skipping."
exit 0
fi
# `npm view` reads a replica that lags the authoritative write path,
# so a freshly/concurrently published version can still 403 here.
# Treat "cannot publish over previously published" as success.
set +e
OUT="$(npm publish --access public 2>&1)"; CODE=$?
set -e
printf '%s\n' "$OUT"
if [ "$CODE" -ne 0 ] && ! printf '%s' "$OUT" | grep -q "cannot publish over the previously published versions"; then
exit "$CODE"
fi
npm publish --access public

go-tag:
needs: [acceptance, release-integrity]
runs-on: ubuntu-latest
permissions:
contents: write
Expand All @@ -84,16 +128,16 @@ jobs:
with:
fetch-depth: 0
- name: Create Go submodule version tag
env:
VERSION: ${{ needs.release-integrity.outputs.version }}
run: |
set -euo pipefail
RAW="${{ github.event.inputs.version || github.event.release.tag_name }}"
VERSION="${RAW#v}"
TAG="sdk/go/v${VERSION}"
git config user.name "agentdrive-bot"
git config user.email "support@agentdrive.run"
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Tag $TAG already exists."
else
git tag "$TAG"
git push origin "$TAG"
echo "Refusing to reuse immutable tag $TAG." >&2
exit 1
fi
git tag "$TAG"
git push origin "$TAG"
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ Full paste-ready blocks: [`docs/add-to-your-agent.md`](docs/add-to-your-agent.md

Generated reproducibly from the reviewed AgentDrive contract via pinned
[OpenAPI Generator](https://openapi-generator.tech/). See
[`sdk/README.md`](sdk/README.md).
[`sdk/README.md`](sdk/README.md). The Phase 1 Python package includes complete
sync and async generated clients; its exact callable and wire reference is
[`docs/python-sdk-api-reference.md`](docs/python-sdk-api-reference.md).

```bash
# Python (once published)
Expand All @@ -71,7 +73,9 @@ npm install @mnexa-ai/agentdrive-sdk
go get github.com/Mnexa-AI/agentdrive-sdk/sdk/go
```

> The bare `agentdrive` package on PyPI is the [stdio MCP companion](https://pypi.org/project/agentdrive/); the REST SDK ships as `agentdrive-sdk`.
> The bare `agentdrive` name on PyPI is a parked `0.0.1` placeholder. The old
> stdio MCP companion is retired; local-file transfers use the hosted MCP upload
> session tools or this REST SDK. The REST SDK ships as `agentdrive-sdk`.

## Links

Expand Down
Loading