diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml new file mode 100644 index 00000000..a1f1ec65 --- /dev/null +++ b/.github/workflows/publish-pypi.yml @@ -0,0 +1,136 @@ +# Publishes agent-learning-kit to PyPI (Trusted Publishing) on merge to main, +# only when the pyproject version is not yet on PyPI. +# Release: bump `version` in pyproject.toml + `uv lock`, merge, approve the +# `pypi` environment deployment. PyPI publisher: pending publisher at +# https://pypi.org/manage/account/publishing/ (repo agent-learning-kit, +# workflow publish-pypi.yml, environment pypi). +name: publish-pypi + +on: + push: + branches: [main] + +permissions: + contents: read + +concurrency: + group: publish-pypi-main + cancel-in-progress: false + +env: + PYPI_PROJECT: agent-learning-kit + UV_VERSION: "0.12.9" + +jobs: + check: + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + publish: ${{ steps.v.outputs.publish }} + version: ${{ steps.v.outputs.version }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0 + with: + version: ${{ env.UV_VERSION }} + - id: v + env: + REF: ${{ github.ref }} + SHA: ${{ github.sha }} + HEADLINE: ${{ github.event.head_commit.message }} + shell: bash + run: | + set -euo pipefail + [[ "$REF" == refs/heads/main ]] || { echo "::error::refusing to publish from $REF"; exit 1; } + version="$(uv version --short)" + [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([a-z0-9.]*)$ ]] || { echo "::error::unexpected version shape"; exit 1; } + echo "version=$version" >> "$GITHUB_OUTPUT" + wheel="agent_learning_kit-${version}-py3-none-any.whl"; sdist="agent_learning_kit-${version}.tar.gz" + body="$(mktemp)" + code="$(curl -sS --max-time 30 --retry 3 --retry-delay 2 -o "$body" -w '%{http_code}' \ + "https://pypi.org/pypi/${PYPI_PROJECT}/json")" + case "$code" in + 404) publish=true; why="first release" ;; + 200) if jq -e --arg v "$version" --arg w "$wheel" --arg s "$sdist" \ + '(.releases[$v] // []) | map(.filename) | (index($w) != null and index($s) != null)' "$body" >/dev/null + then publish=false; why="already on PyPI" + else publish=true; why="not on PyPI"; fi ;; + *) echo "::error::PyPI lookup returned HTTP $code"; exit 1 ;; + esac + echo "publish=$publish" >> "$GITHUB_OUTPUT" + { + echo "## ${PYPI_PROJECT} **${version}** — ${why}" + echo "- commit: \`${SHA}\` — ${HEADLINE%%$'\n'*}" + } >> "$GITHUB_STEP_SUMMARY" + + build: + needs: check + if: needs.check.outputs.publish == 'true' + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@bec219d24cd3e171d82865faccec33120bb574f4 # v10.1.0 + with: + version: ${{ env.UV_VERSION }} + - run: uv build + - run: | + set -euo pipefail + uv venv .smoke --python 3.12 + uv pip install --python .smoke/bin/python dist/*.whl + .smoke/bin/python -c "import fi.simulate.hosted.child_entrypoint, fi.alk.harness" + .smoke/bin/alk --help > /dev/null + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: dist + path: dist/ + if-no-files-found: error + + publish: + needs: [check, build] + if: needs.check.outputs.publish == 'true' + runs-on: ubuntu-latest + timeout-minutes: 10 + environment: pypi + permissions: + id-token: write + contents: read + env: + VERSION: ${{ needs.check.outputs.version }} + steps: + - id: recheck + shell: bash + run: | + set -euo pipefail + wheel="agent_learning_kit-${VERSION}-py3-none-any.whl"; sdist="agent_learning_kit-${VERSION}.tar.gz" + body="$(mktemp)" + code="$(curl -sS --max-time 30 --retry 3 --retry-delay 2 -o "$body" -w '%{http_code}' \ + "https://pypi.org/pypi/${PYPI_PROJECT}/json")" + if [[ "$code" == 200 ]] && jq -e --arg v "$VERSION" --arg w "$wheel" --arg s "$sdist" \ + '(.releases[$v] // []) | map(.filename) | (index($w) != null and index($s) != null)' "$body" >/dev/null; then + echo "go=false" >> "$GITHUB_OUTPUT" + elif [[ "$code" == 200 || "$code" == 404 ]]; then + echo "go=true" >> "$GITHUB_OUTPUT" + else + echo "::error::PyPI lookup returned HTTP $code"; exit 1 + fi + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + if: steps.recheck.outputs.go == 'true' + with: + name: dist + path: dist/ + - if: steps.recheck.outputs.go == 'true' + shell: bash + run: | + set -euo pipefail + expected=$(printf '%s\n' "agent_learning_kit-${VERSION}-py3-none-any.whl" "agent_learning_kit-${VERSION}.tar.gz" | sort) + [[ "$(ls -1 dist/ | sort)" == "$expected" ]] || { echo "::error::dist/ does not match version ${VERSION}"; ls -la dist/; exit 1; } + - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1 + if: steps.recheck.outputs.go == 'true' + with: + attestations: true + skip-existing: true diff --git a/README.md b/README.md index 1635db34..dbed42df 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- Future AGI + Future AGI

Agent Learning Kit

@@ -9,20 +9,20 @@

- Apache-2.0 + Apache-2.0 · - Docs + Docs · - Contributing + Contributing · - Security + Security · - V1 roadmap + V1 roadmap · - Library inventory + Library inventory

-![Agent Learning lifecycle blueprint](docs/assets/hero-agent-blueprint.jpg) +![Agent Learning lifecycle blueprint](https://raw.githubusercontent.com/future-agi/agent-learning-kit/main/docs/assets/hero-agent-blueprint.jpg) Agent Learning Kit is the local-first SDK and CLI for testing, simulating, red-teaming, and optimizing AI agents. @@ -53,10 +53,10 @@ Point it at an agent's source and it reads what that agent verifiably is, builds tools act on, and writes test scenarios that are each proved before they are kept. It is driven as a conversation, in a terminal or on a web page. -- **[Start here](src/fi/alk/harness/README.md)**: setup from nothing, then how to use it -- **[The web page](harness-ui/README.md)**: the same harness as a chat, on `localhost:8777` -- **[How it works](src/fi/alk/harness/HOW-IT-WORKS.md)** and - **[why it is shaped this way](src/fi/alk/harness/DESIGN.md)** +- **[Start here](https://github.com/future-agi/agent-learning-kit/blob/main/src/fi/alk/harness/README.md)**: setup from nothing, then how to use it +- **[The web page](https://github.com/future-agi/agent-learning-kit/blob/main/harness-ui/README.md)**: the same harness as a chat, on `localhost:8777` +- **[How it works](https://github.com/future-agi/agent-learning-kit/blob/main/src/fi/alk/harness/HOW-IT-WORKS.md)** and + **[why it is shaped this way](https://github.com/future-agi/agent-learning-kit/blob/main/src/fi/alk/harness/DESIGN.md)** OpenEnv/Gymnasium shapes are compatibility inputs, not the product center. Agent Learning Kit is the primary runtime and release contract, and the bar is @@ -65,22 +65,22 @@ OpenEnv/Gymnasium-shaped traces remain compatibility evidence inside that bar. ## Install -PyPI and npm publishing land at the v1 launch. Today, install from source: +Install from PyPI: ```bash -git clone https://github.com/future-agi/agent-learning-kit -cd agent-learning-kit -pip install -e . +pip install agent-learning-kit ``` -(or `uv sync` for contributors) - -At launch: +To develop against source (contributors): ```bash -pip install agent-learning-kit +git clone https://github.com/future-agi/agent-learning-kit +cd agent-learning-kit +uv sync # or: pip install -e . ``` +(npm publishing of the TypeScript SDK lands at the v1 launch.) + Optional Python extras: ```bash @@ -90,7 +90,7 @@ pip install "agent-learning-kit[all]" ``` TypeScript evaluation package (npm at launch; today build from -[`typescript/agent-learning-kit`](typescript/agent-learning-kit)): +[`typescript/agent-learning-kit`](https://github.com/future-agi/agent-learning-kit/blob/main/typescript/agent-learning-kit)): ```bash pnpm add @future-agi/agent-learning-kit @@ -111,7 +111,7 @@ Then run the golden path against the bundled example manifests. The credential, so any placeholder value works. > Prefer the SDK spine over the CLI? -> [Spec + Runner](docs/simulate/spec-and-runner.md) runs the same simulation as +> [Spec + Runner](https://github.com/future-agi/agent-learning-kit/blob/main/docs/simulate/spec-and-runner.md) runs the same simulation as > one `SimulationSpec` fed to one `SimulationRunner` — the plug-and-play surface > behind every simulation. @@ -154,7 +154,7 @@ Optional platform mode: to use Future AGI platform-backed evaluation, set `AGENT_LEARNING_API_KEY` (it takes precedence over the `FUTURE_AGI_API_KEY` and `FI_API_KEY` aliases), or call `configure(api_key="...")` from `fi.alk`. See -[docs/reference/configure.md](docs/reference/configure.md). +[docs/reference/configure.md](https://github.com/future-agi/agent-learning-kit/blob/main/docs/reference/configure.md). Cut local release proof: @@ -203,30 +203,30 @@ The public SDK is `agent-learning-kit`, the Python namespace is The active `ai-evaluation` code is included here under `src/fi/evals`, with its TypeScript SDK source under `typescript/agent-learning-kit/src`. The `simulate-sdk` and `agent-opt` engine code is included under `src/fi/simulate` -and `src/fi/opt`. See [LIBRARIES.md](LIBRARIES.md) for the complete source map. +and `src/fi/opt`. See [LIBRARIES.md](https://github.com/future-agi/agent-learning-kit/blob/main/LIBRARIES.md) for the complete source map. The ai-evaluation source inventory used by `agent-learn release-check` lives at the ai-evaluation source inventory (maintained in the internal-docs repo). ## Repository Map -- [`examples/`](examples): runnable cookbooks and manifests. -- [`src/fi/alk`](src/fi/alk): public Python SDK facade and CLI. -- [`src/fi/evals`](src/fi/evals): active `ai-evaluation` engine code. -- [`src/fi/simulate`](src/fi/simulate): migrated `simulate-sdk` engine code. -- [`src/fi/opt`](src/fi/opt): migrated `agent-opt` engine code. -- [`typescript/agent-learning-kit`](typescript/agent-learning-kit): public +- [`examples/`](https://github.com/future-agi/agent-learning-kit/blob/main/examples): runnable cookbooks and manifests. +- [`src/fi/alk`](https://github.com/future-agi/agent-learning-kit/blob/main/src/fi/alk): public Python SDK facade and CLI. +- [`src/fi/evals`](https://github.com/future-agi/agent-learning-kit/blob/main/src/fi/evals): active `ai-evaluation` engine code. +- [`src/fi/simulate`](https://github.com/future-agi/agent-learning-kit/blob/main/src/fi/simulate): migrated `simulate-sdk` engine code. +- [`src/fi/opt`](https://github.com/future-agi/agent-learning-kit/blob/main/src/fi/opt): migrated `agent-opt` engine code. +- [`typescript/agent-learning-kit`](https://github.com/future-agi/agent-learning-kit/blob/main/typescript/agent-learning-kit): public TypeScript package, including the active evaluation SDK source. -- [`docs/index.md`](docs/index.md): full documentation index. -- [`ROADMAP.md`](ROADMAP.md): public v1 roadmap and post-v1 extensions. -- [`LIBRARIES.md`](LIBRARIES.md): source map for the consolidated engines. -- [`CONTRIBUTING.md`](CONTRIBUTING.md): local development and PR workflow. -- [`SECURITY.md`](SECURITY.md): vulnerability reporting policy. -- [`LICENSE`](LICENSE): Apache-2.0 license. -- [`NOTICE`](NOTICE): Apache notice metadata. +- [`docs/index.md`](https://github.com/future-agi/agent-learning-kit/blob/main/docs/index.md): full documentation index. +- [`ROADMAP.md`](https://github.com/future-agi/agent-learning-kit/blob/main/ROADMAP.md): public v1 roadmap and post-v1 extensions. +- [`LIBRARIES.md`](https://github.com/future-agi/agent-learning-kit/blob/main/LIBRARIES.md): source map for the consolidated engines. +- [`CONTRIBUTING.md`](https://github.com/future-agi/agent-learning-kit/blob/main/CONTRIBUTING.md): local development and PR workflow. +- [`SECURITY.md`](https://github.com/future-agi/agent-learning-kit/blob/main/SECURITY.md): vulnerability reporting policy. +- [`LICENSE`](https://github.com/future-agi/agent-learning-kit/blob/main/LICENSE): Apache-2.0 license. +- [`NOTICE`](https://github.com/future-agi/agent-learning-kit/blob/main/NOTICE): Apache notice metadata. ## Development -New public SDK development belongs here. See [DEVELOPMENT.md](DEVELOPMENT.md) +New public SDK development belongs here. See [DEVELOPMENT.md](https://github.com/future-agi/agent-learning-kit/blob/main/DEVELOPMENT.md) for the boundary between this package and the backing engine repos. ```bash @@ -271,12 +271,12 @@ extensions land post-v1 without weakening any gate. ## Community -- Contributions: [CONTRIBUTING.md](CONTRIBUTING.md) -- Code of conduct: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) -- Security reports: [SECURITY.md](SECURITY.md) -- License: [Apache-2.0](LICENSE) +- Contributions: [CONTRIBUTING.md](https://github.com/future-agi/agent-learning-kit/blob/main/CONTRIBUTING.md) +- Code of conduct: [CODE_OF_CONDUCT.md](https://github.com/future-agi/agent-learning-kit/blob/main/CODE_OF_CONDUCT.md) +- Security reports: [SECURITY.md](https://github.com/future-agi/agent-learning-kit/blob/main/SECURITY.md) +- License: [Apache-2.0](https://github.com/future-agi/agent-learning-kit/blob/main/LICENSE) ## Deep Dive The full documentation set — quickstarts, per-track guides, framework pages, -and reference material — starts at [docs/index.md](docs/index.md). +and reference material — starts at [docs/index.md](https://github.com/future-agi/agent-learning-kit/blob/main/docs/index.md). diff --git a/pyproject.toml b/pyproject.toml index 14396cbf..0670bc6e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,6 @@ [build-system] -requires = ["hatchling"] +# Bounded: the build backend is the one artifact input uv.lock does not cover. +requires = ["hatchling>=1.27,<2"] build-backend = "hatchling.build" [project]