Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
cc5f583
feat: add Python distribution for agentic-api
franciscojavierarceo Aug 24, 2026
e519057
fix: stabilize Python CI matrix
franciscojavierarceo Aug 24, 2026
aa1463e
feat: harden Python CLI developer experience
franciscojavierarceo Aug 26, 2026
6d4613b
ci: avoid oversized Python target cache
franciscojavierarceo Aug 26, 2026
5a3db2d
fix: align Python release checks with workspace version
franciscojavierarceo Aug 26, 2026
dc942a3
test: derive installed CLI version expectation
franciscojavierarceo Aug 26, 2026
7c734e2
fix: improve Python launcher failure UX
franciscojavierarceo Aug 26, 2026
12cfa1d
fix: bound packaged binary version probes
franciscojavierarceo Aug 26, 2026
c859337
fix: clarify missing Python launcher errors
franciscojavierarceo Aug 26, 2026
14a551d
fix: clarify unsupported local platforms
franciscojavierarceo Aug 26, 2026
7844322
fix: reject blank local models
franciscojavierarceo Aug 26, 2026
30f7b59
fix: address Python package review findings
franciscojavierarceo Aug 26, 2026
8f1dd09
fix: find binaries beside prefixed console scripts
franciscojavierarceo Aug 26, 2026
5bf02a5
test: remove readiness timeout race
franciscojavierarceo Aug 26, 2026
32e4cfe
fix: address Python launcher review feedback
franciscojavierarceo Aug 26, 2026
abc0b79
fix: address launcher review feedback
franciscojavierarceo Aug 26, 2026
10efee4
test: update installed gateway command expectation
franciscojavierarceo Aug 26, 2026
c5f2f00
chore: resolve main branch conflicts
franciscojavierarceo Aug 27, 2026
97b96f4
Merge branch 'main' into codex/agentic-api-python-0.4.0
franciscojavierarceo Aug 28, 2026
26a4b0b
fix: address Copilot review feedback
franciscojavierarceo Aug 28, 2026
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
110 changes: 110 additions & 0 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: Python

run-name: Python wheel build and validation

on:
pull_request:
paths:
- ".github/workflows/python.yml"
- ".github/workflows/release-python.yml"
- "Cargo.lock"
- "Cargo.toml"
- "crates/**"
- "README.md"
- "docs/**"
- "pyproject.toml"
- "python-build-constraints.txt"
- "python/**"
- "scripts/check-python-wheel.sh"
- "scripts/validate-python-release-version.sh"
- "tests/python/**"
merge_group:
push:
branches:
- main
paths:
- ".github/workflows/python.yml"
- ".github/workflows/release-python.yml"
- "Cargo.lock"
- "Cargo.toml"
- "crates/**"
- "README.md"
- "docs/**"
- "pyproject.toml"
- "python-build-constraints.txt"
- "python/**"
- "scripts/check-python-wheel.sh"
- "scripts/validate-python-release-version.sh"
- "tests/python/**"

concurrency:
group: ${{ github.workflow }}-${{ github.ref == 'refs/heads/main' && github.run_id || github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
python:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: |
pyproject.toml
python-build-constraints.txt

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: 1.98.0
components: clippy, rustfmt

- name: Cache cargo registry and build
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: cargo-python-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('Cargo.lock', 'python-build-constraints.txt') }}
restore-keys: |
cargo-python-${{ runner.os }}-${{ matrix.python-version }}-
cargo-python-${{ runner.os }}-
cargo-${{ runner.os }}-

- name: Install uv
run: python -m pip install --constraint python-build-constraints.txt uv

- name: Build and validate wheel
run: |
set -euo pipefail
expected_version="$(cargo metadata --format-version 1 --no-deps \
| jq -r '.packages[] | select(.name == "agentic-server") | .version')"
if [ -z "$expected_version" ] || [ "$expected_version" = "null" ]; then
echo "::error::agentic-server workspace version could not be determined"
exit 1
fi
uv venv --python "${{ matrix.python-version }}" .venv
uv pip install --python .venv/bin/python --constraint python-build-constraints.txt maturin pytest
wheel_dir="$RUNNER_TEMP/agentic-api-wheels-${{ matrix.python-version }}"
mkdir -p "$wheel_dir"
.venv/bin/python -m maturin build --release --locked --out "$wheel_dir"
wheel_path="$(
.venv/bin/python -c 'from pathlib import Path; import sys; matches = sorted(Path(sys.argv[1]).glob(f"agentic_api-{sys.argv[2]}-*.whl")); assert len(matches) == 1, f"expected exactly one wheel, found {[path.name for path in matches]}"; print(matches[0])' "$wheel_dir" "$expected_version"
)"
uv pip install --python .venv/bin/python "$wheel_path"
AGENTIC_API_TEST_WHEEL="$wheel_path" .venv/bin/python -m pytest tests/python -q
AGENTIC_API_CHECK_PYTHON=.venv/bin/python \
AGENTIC_API_CHECK_SCRIPTS_DIR=.venv/bin \
AGENTIC_API_EXPECTED_VERSION="$expected_version" \
scripts/check-python-wheel.sh "$wheel_path"
172 changes: 172 additions & 0 deletions .github/workflows/release-python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
name: Release Python

run-name: Release Python wheels (${{ inputs.version }})

on:
workflow_dispatch:
inputs:
version:
description: "Build-only Python release version already merged into main"
required: true
type: string
default: "0.5.0"

concurrency:
group: release-python-${{ inputs.version }}
cancel-in-progress: false

permissions:
contents: read

jobs:
build-wheels:
name: Build ${{ matrix.target }} wheel artifact
runs-on: ${{ matrix.runs-on }}
if: github.ref == 'refs/heads/main'
env:
AGENTIC_API_RELEASE_VERSION: ${{ inputs.version }}
strategy:
fail-fast: false
matrix:
include:
- runs-on: ubuntu-22.04
os: linux
target: linux-x86_64
wheel-tag: py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64
- runs-on: macos-15-intel
os: macos
target: macos-x86_64
wheel-tag: py3-none-macosx_10_12_x86_64
deployment-target: "10.12"
- runs-on: macos-14
os: macos
target: macos-arm64
wheel-tag: py3-none-macosx_11_0_arm64
deployment-target: "11.0"
steps:
- name: Checkout code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Verify build-only release gate version
run: scripts/validate-python-release-version.sh

- name: Set up Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.12"
cache: pip
cache-dependency-path: |
pyproject.toml
python-build-constraints.txt

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: 1.98.0

- name: Cache cargo registry and build
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target/release-python/${{ matrix.target }}
key: cargo-release-python-${{ runner.os }}-${{ matrix.target }}-${{ hashFiles('Cargo.lock', 'python-build-constraints.txt') }}
restore-keys: |
cargo-release-python-${{ runner.os }}-${{ matrix.target }}-
cargo-${{ runner.os }}-

- name: Install uv
run: python -m pip install --constraint python-build-constraints.txt uv

- name: Verify version agreement and prepare artifact directory
id: prepare
run: |
set -euo pipefail
scripts/validate-python-release-version.sh
requested_version="$AGENTIC_API_RELEASE_VERSION"
wheel_dir="target/release-python/${{ matrix.target }}/wheels"
cargo_version="$(cargo metadata --format-version 1 --no-deps \
| jq -r '.packages[] | select(.name == "agentic-server") | .version')"
core_version="$(cargo metadata --format-version 1 --no-deps \
| jq -r '.packages[] | select(.name == "agentic-server-core") | .version')"

if [ -z "$cargo_version" ] || [ "$cargo_version" = "null" ]; then
echo "::error::agentic-server package not found in workspace metadata"
exit 1
fi

if [ "$cargo_version" != "$core_version" ]; then
echo "::error::agentic-server ($cargo_version) and agentic-server-core ($core_version) versions differ"
exit 1
fi

if [ "$cargo_version" != "$requested_version" ]; then
echo "::error::workspace version $cargo_version does not match requested release version $requested_version"
exit 1
fi

rm -rf "$wheel_dir"
mkdir -p "$wheel_dir"
uv venv --python 3.12 .venv
uv pip install --python .venv/bin/python --constraint python-build-constraints.txt maturin pytest
echo "wheel_dir=$wheel_dir" >> "$GITHUB_OUTPUT"

- name: Build pinned manylinux2014 x86_64 wheel
if: matrix.os == 'linux'
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
with:
command: build
args: --release --locked --out ${{ steps.prepare.outputs.wheel_dir }}
container: quay.io/pypa/manylinux2014_x86_64@sha256:95440e0e72dd3a81dc8d2cf59a84d57af661456620f5bc821ff92048d0e54ff9
manylinux: "2014"
maturin-version: v1.14.1
rust-toolchain: 1.98.0
target: x86_64-unknown-linux-gnu

- name: Build macOS wheel
if: matrix.os == 'macos'
env:
CARGO_TARGET_DIR: target/release-python/${{ matrix.target }}/cargo
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.deployment-target }}
run: >-
.venv/bin/python -m maturin build --release --locked
--out "${{ steps.prepare.outputs.wheel_dir }}"

- name: Validate exact wheel artifact
id: build
run: |
set -euo pipefail
scripts/validate-python-release-version.sh
requested_version="$AGENTIC_API_RELEASE_VERSION"
wheel_dir="${{ steps.prepare.outputs.wheel_dir }}"
expected_wheel_tag="${{ matrix.wheel-tag }}"
wheel_path="$wheel_dir/agentic_api-${requested_version}-${expected_wheel_tag}.whl"

if [ ! -f "$wheel_path" ]; then
echo "::error::expected wheel not found: $wheel_path"
find "$wheel_dir" -maxdepth 1 -type f -name '*.whl' -print
exit 1
fi

wheel_count="$(find "$wheel_dir" -maxdepth 1 -type f -name '*.whl' | wc -l | tr -d ' ')"
if [ "$wheel_count" != "1" ]; then
echo "::error::expected exactly one wheel in $wheel_dir; found $wheel_count"
exit 1
fi

uv pip install --python .venv/bin/python "$wheel_path"
AGENTIC_API_TEST_WHEEL="$wheel_path" .venv/bin/python -m pytest tests/python -q
AGENTIC_API_CHECK_PYTHON=.venv/bin/python \
AGENTIC_API_CHECK_SCRIPTS_DIR=.venv/bin \
AGENTIC_API_EXPECTED_VERSION="$requested_version" \
AGENTIC_API_EXPECTED_WHEEL_TAG="$expected_wheel_tag" \
scripts/check-python-wheel.sh "$wheel_path"
echo "wheel_path=$wheel_path" >> "$GITHUB_OUTPUT"

- name: Upload wheel artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: agentic-api-${{ inputs.version }}-${{ matrix.target }}
path: ${{ steps.build.outputs.wheel_path }}
if-no-files-found: error
12 changes: 11 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ This repository is Rust-first under the `vllm-project` GitHub organization.

- **Rust** -- primary and active implementation language at the repo root.
- **Docs** -- MkDocs documentation in `docs/`.
- **Python gateway code has been removed** as part of the migration plan.
- **Python** -- a lightweight distribution and launcher for the packaged Rust gateway; the gateway implementation
remains Rust-first.

## Terminology

Expand All @@ -27,6 +28,9 @@ This repository is Rust-first under the `vllm-project` GitHub organization.
├── crates/agentic-server/ # Axum binary, transport handlers, and configuration
├── crates/agentic-server-core/ # Protocol types, execution, tools, and persistence
├── crates/agentic-praxis/ # Praxis integration
├── python/agentic_api/ # Python distribution, diagnostics, and launcher
├── tests/python/ # Python package and CLI tests
├── pyproject.toml # Python wheel build metadata
├── Cargo.toml # Workspace manifest and shared dependencies/lints
└── docs/ # Documentation (MkDocs)
```
Expand All @@ -44,6 +48,12 @@ cargo build

```bash
cargo test

# Python distribution and CLI tests
uv run --python 3.12 --with maturin==1.14.1 --with pytest==9.1.1 python -m pytest tests/python

# Source-install CLI E2E (also exercises the packaged wheel build)
python3 scripts/tests/agentic-cli-e2e-test.py
```

- Before adding or updating replay cassettes, read `crates/agentic-server-core/tests/cassettes/README.md` and use its
Expand Down
38 changes: 37 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ______________________________________________________________________

vLLM gives you state-of-the-art inference throughput. But real agentic applications need more than raw tokens: they need **conversation state, tool-call loops, and multi-turn orchestration**. Today, all of that complexity lives in your client code.

**Agentic API moves it server-side.** It is a Rust-native gateway that sits in front of vLLM and owns the stateful agentic APIs, starting with an OpenAI-compatible [Responses API](https://platform.openai.com/docs/api-reference/responses). Your application makes *one API call* and the server handles the rest: state hydration, tool execution, streaming, and continuation.
**Agentic API moves it server-side.** It is a Rust-native gateway that sits in front of vLLM and owns the stateful agentic APIs, starting with an OpenAI-compatible [Responses API](https://platform.openai.com/docs/api-reference/responses). vLLM is one supported backend, not part of the Agentic API product name. Your application makes *one API call* and the server handles the rest: state hydration, tool execution, streaming, and continuation.

```mermaid
flowchart LR
Expand Down Expand Up @@ -120,6 +120,42 @@ Use `AGENTIC_CODEX_BIN` or `AGENTIC_CLAUDE_BIN` to override harness binary disco
`--quiet` for minimal lifecycle output. Use `--yolo` only in an externally isolated environment; it skips Claude
permission checks and disables Codex approvals and sandboxing.

### Python distribution

The `agentic-api` wheel packages the Rust gateway and a small Python launcher. This release produces wheel artifacts
for 0.5.0 as a build-only release: download the wheel for your platform from the release workflow, then install that local file. It is
not published on PyPI yet.

```bash
WHEEL_PATH=/absolute/path/to/agentic_api-PLATFORM.whl
uv pip install "$WHEEL_PATH"
agentic-api serve --vllm-base-url http://existing-vllm:8000

uv pip install "agentic-api[local] @ file://$WHEEL_PATH"
agentic-api serve --model MODEL_ID
```

The base install is for remote mode and does not install vLLM. The `[local]` extra installs the pinned vLLM runtime so
the launcher can manage a local vLLM process on supported Linux hosts.

Use `agentic-api --version` for a quick install check and `agentic-api doctor --mode remote --json` when an agent or
script needs machine-readable diagnostics.

#### After PyPI publication

These public-index and `uvx` examples apply only after the PyPI publication gate for a future release:

```bash
uv pip install agentic-api
uv pip install "agentic-api[local]"
uvx --from agentic-api agentic-api doctor
uvx --from agentic-api agentic-api serve --vllm-base-url http://existing-vllm:8000
```

The Rust-native `agentic` CLI remains supported for `run codex`, `run claude`, `serve`, and `validate`. For the full
installation walkthrough, managed-vLLM passthrough examples, `doctor` output, and known-good model profiles, see
[Python installation and workflows](docs/guides/python-installation.md).

For Claude sessions, Agentic API always sets both `--effort medium` and `CLAUDE_CODE_EFFORT_LEVEL=medium`; the
environment variable is intentional because Claude Code gives it precedence over the command-line effort flag.
Qwen3.8-27B's vLLM chat template accepts `low`, `medium`, and `xhigh` reasoning effort values but not Claude Code's
Expand Down
6 changes: 5 additions & 1 deletion crates/agentic-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,11 @@ fn oidc_config_from_values(
}

#[derive(Parser)]
#[command(name = "agentic-server", about = "Stateful API gateway for vLLM Responses API")]
#[command(
name = "agentic-server",
about = "Stateful API gateway for vLLM Responses API",
version
)]
struct Cli {
#[command(subcommand)]
command: Option<Commands>,
Expand Down
Loading