Skip to content

Commit 6066be4

Browse files
committed
Fix abi3 wheel publish workflow; release 1.2.26
1 parent 48b95dc commit 6066be4

7 files changed

Lines changed: 51 additions & 71 deletions

File tree

.github/workflows/publish-pypi.yml

Lines changed: 21 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,10 @@ permissions:
1111

1212
jobs:
1313
build-linux:
14-
name: Build Linux wheels (${{ matrix.python-tag }})
14+
name: Build Linux wheel
1515
runs-on: ubuntu-latest
16-
strategy:
17-
fail-fast: false
18-
matrix:
19-
python-tag:
20-
- cp310-cp310
21-
- cp311-cp311
22-
- cp312-cp312
2316
env:
24-
PYTHON_TAG: ${{ matrix.python-tag }}
17+
PYTHON_TAG: cp310-cp310
2518
steps:
2619
- name: Check out repository
2720
uses: actions/checkout@v4
@@ -65,28 +58,21 @@ jobs:
6558
- name: Upload wheel artifact
6659
uses: actions/upload-artifact@v4
6760
with:
68-
name: wheels-linux-${{ matrix.python-tag }}
61+
name: wheels-linux
6962
path: wheelhouse/*.whl
7063
if-no-files-found: error
7164

7265
build-macos:
73-
name: Build macOS wheels (py${{ matrix.python }})
66+
name: Build macOS wheel
7467
runs-on: macos-latest
75-
strategy:
76-
fail-fast: false
77-
matrix:
78-
python:
79-
- "3.10"
80-
- "3.11"
81-
- "3.12"
8268
steps:
8369
- name: Check out repository
8470
uses: actions/checkout@v4
8571

8672
- name: Set up Python
8773
uses: actions/setup-python@v5
8874
with:
89-
python-version: ${{ matrix.python }}
75+
python-version: "3.10"
9076

9177
- name: Set up Rust
9278
uses: dtolnay/rust-toolchain@stable
@@ -131,28 +117,21 @@ jobs:
131117
- name: Upload wheel artifact
132118
uses: actions/upload-artifact@v4
133119
with:
134-
name: wheels-macos-py${{ matrix.python }}
120+
name: wheels-macos
135121
path: dist/*.whl
136122
if-no-files-found: error
137123

138124
build-windows:
139-
name: Build Windows wheels (py${{ matrix.python }})
125+
name: Build Windows wheel
140126
runs-on: windows-latest
141-
strategy:
142-
fail-fast: false
143-
matrix:
144-
python:
145-
- "3.10"
146-
- "3.11"
147-
- "3.12"
148127
steps:
149128
- name: Check out repository
150129
uses: actions/checkout@v4
151130

152131
- name: Set up Python
153132
uses: actions/setup-python@v5
154133
with:
155-
python-version: ${{ matrix.python }}
134+
python-version: "3.10"
156135

157136
- name: Set up Rust
158137
uses: dtolnay/rust-toolchain@stable
@@ -162,18 +141,6 @@ jobs:
162141
python -m pip install --upgrade pip
163142
python -m pip install build tomli
164143
165-
- name: Pin Strawberry Perl for vendored OpenSSL
166-
shell: pwsh
167-
run: |
168-
$perl = 'C:\Strawberry\perl\bin\perl.exe'
169-
if (Test-Path $perl) {
170-
"OPENSSL_SRC_PERL=$perl" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
171-
"PERL=$perl" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
172-
& $perl -e "print $^X"
173-
} else {
174-
throw 'Strawberry Perl not found at C:\Strawberry\perl\bin\perl.exe'
175-
}
176-
177144
- name: Build and stage the binding
178145
shell: pwsh
179146
run: |
@@ -204,7 +171,7 @@ jobs:
204171
- name: Upload wheel artifact
205172
uses: actions/upload-artifact@v4
206173
with:
207-
name: wheels-windows-py${{ matrix.python }}
174+
name: wheels-windows
208175
path: dist/*.whl
209176
if-no-files-found: error
210177

@@ -223,9 +190,21 @@ jobs:
223190
pattern: wheels-*
224191
merge-multiple: true
225192

193+
- name: Verify publish payload
194+
run: |
195+
python3 - <<'PY'
196+
from pathlib import Path
197+
198+
wheels = sorted(Path("dist").glob("*.whl"))
199+
print("wheels:", [wheel.name for wheel in wheels])
200+
if len(wheels) != 3:
201+
raise SystemExit(f"expected exactly 3 platform wheels, found {len(wheels)}")
202+
PY
203+
226204
- name: Publish distributions
227205
uses: pypa/gh-action-pypi-publish@release/v1
228206
with:
229207
packages-dir: dist/
230208
password: ${{ secrets.PYPI_TOKEN }}
209+
skip-existing: true
231210
user: __token__

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
99

1010
### Added
1111

12+
## [1.2.26] - 2026-03-24
13+
14+
### Fixed
15+
- Fixed the PyPI release workflow to build exactly one Python 3.10 `cp310-abi3` wheel per platform, eliminating duplicate wheel filenames with different binary contents from the old per-version matrix.
16+
- Made the PyPI publish step rerunnable by skipping files that already exist, which prevents partial uploads from blocking a release retry.
17+
- Updated the package metadata and release docs to describe the restored in-repo Rust binding instead of the retired external-binding flow.
18+
1219
## [1.2.25] - 2026-03-24
1320

1421
### Fixed

docs/README.md

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ Inspired by [smolagents](https://github.com/huggingface/smolagents) and [Pi](htt
88

99
> **Beta** — TinyAgent is usable but not production-ready. APIs may change between minor versions.
1010
11-
> **Note:** The optional `tinyagent._alchemy` binding now lives in
12-
> `https://github.com/tunahorse/tinyagent-alchemy` and is not built from this repo.
11+
> **Note:** The optional `tinyagent._alchemy` binding is built from the in-repo
12+
> Rust crate and shipped in supported PyPI wheels.
1313
1414
## Overview
1515

@@ -20,14 +20,14 @@ TinyAgent provides a lightweight foundation for creating conversational AI agent
2020
- **Event-driven**: Subscribe to agent events for real-time UI updates
2121
- **Provider agnostic**: Works with any OpenAI-compatible `/chat/completions` endpoint (OpenRouter, OpenAI, Chutes, local servers)
2222
- **Prompt caching**: Reduce token costs and latency with Anthropic-style cache breakpoints
23-
- **Provider paths**: Optional external alchemy binding adapter plus proxy integration
23+
- **Provider paths**: Optional in-repo alchemy binding plus proxy integration
2424
- **Type-safe**: Full type hints throughout
2525

2626
## Quick Start
2727

2828
This example uses the optional `tinyagent._alchemy` binding via
29-
`tinyagent.alchemy_provider`. Install that binding from the external repo first,
30-
or use the proxy path instead.
29+
`tinyagent.alchemy_provider`. Install a wheel that includes the binding for your
30+
platform, or use the proxy path instead.
3131

3232
```python
3333
import asyncio
@@ -72,8 +72,8 @@ Optional binding:
7272

7373
- PyPI wheels may include the compiled `tinyagent._alchemy` extension for supported platforms,
7474
but the source distribution does not.
75-
- Install/build `tinyagent._alchemy` from `https://github.com/tunahorse/tinyagent-alchemy`
76-
if you want `stream_alchemy_openai_completions` and no matching wheel is available.
75+
- Build `tinyagent._alchemy` from the in-repo `rust/` crate if you want
76+
`stream_alchemy_openai_completions` and no matching wheel is available.
7777
- Otherwise, use the proxy path in `tinyagent.proxy`.
7878

7979
## Core Concepts
@@ -161,15 +161,11 @@ Cache breakpoints are automatically placed on user message content blocks so the
161161

162162
## Optional Binding: `tinyagent._alchemy`
163163

164-
This repo keeps `tinyagent/alchemy_provider.py` as a compatibility adapter for the
165-
optional external `tinyagent._alchemy` extension. The binding source, build
166-
instructions, and low-level binding API now live in:
164+
This repo keeps `tinyagent/alchemy_provider.py` as the Python adapter for the
165+
optional `tinyagent._alchemy` extension built from the in-repo `rust/` crate.
167166

168-
- `https://github.com/tunahorse/tinyagent-alchemy`
169-
170-
The compiled path is still useful when you want OpenAI-compatible streaming
171-
without routing through a separate proxy, but it is no longer bundled or built
172-
from this repository.
167+
The compiled path is useful when you want OpenAI-compatible streaming without
168+
routing through a separate proxy.
173169

174170
### Using via TinyAgent
175171

@@ -218,7 +214,7 @@ agent.set_model(
218214
)
219215
```
220216

221-
Smoke validation after installing the external binding:
217+
Smoke validation after installing a wheel with the binding:
222218

223219
- `uv run python scripts/smoke_rust_tool_calls_three_providers.py`
224220

@@ -252,7 +248,7 @@ tinyagent/
252248
├── agent_tool_execution.py # Tool execution helpers
253249
├── agent_types.py # Type definitions
254250
├── caching.py # Prompt caching utilities
255-
├── alchemy_provider.py # Adapter for the optional external binding
251+
├── alchemy_provider.py # Adapter for the optional Rust binding
256252
├── proxy.py # Proxy server integration
257253
└── proxy_event_handlers.py # Proxy event parsing
258254
```

docs/releasing-alchemy-binding.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ platform wheels.
5252
- `HARNESS.md`
5353
- records the release gate for wheels expected to ship `_alchemy`
5454
- `.github/workflows/publish-pypi.yml`
55-
- builds Linux (manylinux), macOS, and Windows release wheels from the in-repo binding
55+
- builds one Python 3.10 `abi3` wheel per platform from the in-repo binding
5656
- repairs Linux wheels into PyPI-acceptable `manylinux` artifacts before upload
5757
- smoke-tests each built wheel in a clean virtualenv before publishing
5858
- publishes the built distributions to PyPI with the repo `PYPI_TOKEN` secret
@@ -150,6 +150,7 @@ On GitHub release publish or manual dispatch, it:
150150

151151
- checks out this repo
152152
- builds the in-repo binding on `ubuntu-latest` (manylinux), `macos-latest`, and `windows-latest`
153+
- uses Python 3.10 once per platform so the `cp310-abi3` wheel filename is unique and stable
153154
- stages the binding into `tinyagent/`
154155
- runs `python3 scripts/check_release_binding.py --require-present`
155156
- builds the `tiny-agent-os` wheel
@@ -227,7 +228,7 @@ This keeps the release contract simple:
227228

228229
The release contract is now:
229230

230-
1. build `_alchemy` from the external binding repo
231+
1. build `_alchemy` from the in-repo `rust/` crate
231232
2. copy it into `tinyagent/`
232233
3. run `python3 scripts/check_release_binding.py --require-present`
233234
4. build the wheel with `uv build --wheel`

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "tiny-agent-os"
7-
version = "1.2.25"
7+
version = "1.2.26"
88
description = "Python agent loop"
99
readme = "README.md"
1010
requires-python = ">=3.10"

tinyagent/alchemy_provider.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
"""Compatibility provider for the optional tinyagent-alchemy binding.
1+
"""Compatibility provider for the optional tinyagent._alchemy binding.
22
3-
This module keeps the Python-side adapter for the external `tinyagent._alchemy`
4-
extension. The binding itself is maintained outside this repo:
5-
6-
https://github.com/tunahorse/tinyagent-alchemy
3+
This module keeps the Python-side adapter for the in-repo `tinyagent._alchemy`
4+
extension built from `rust/`.
75
86
Important limitations:
97
- The binding currently dispatches only `openai-completions` and
@@ -132,9 +130,8 @@ def _get_alchemy_module() -> _AlchemyModule:
132130
)
133131
raise RuntimeError(
134132
"Failed to import the optional alchemy binding. "
135-
"Install the optional binding from "
136-
"https://github.com/tunahorse/tinyagent-alchemy if it is not "
137-
"already installed. "
133+
"Install a wheel that includes tinyagent._alchemy or build the "
134+
"binding from the in-repo rust crate if it is not already installed. "
138135
f"Import failures: {import_failures}"
139136
) from cause
140137
return _ALCHEMY_MODULE

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)