Skip to content

v0.61.0

Choose a tag to compare

@github-actions github-actions released this 20 Sep 17:12
4ceba21

[v0.61.0] - 2026-09-20

Added

  • Claude Opus 5, Claude Fable 5 and Claude Fable 5.1 join the Anthropic backend, and Opus 5 the two hosted profiles: claude-5-opus, claude-5-fable and claude-5.1-fable are served on Anthropic's own model ids, and all three are reachable on Pipelex Manifold through Bedrock's global.anthropic.* endpoints, the way every other Claude already is. Only Opus 5 is served on the Pipelex Gateway: Bedrock refuses both Fables through Portkey with data retention mode 'default' is not available for this model, a mode no model spec can set, so listing them there would publish handles that fail on every request. All of them take text, images and PDF, cap output at 128k tokens, and think adaptively with the temperature parameter refused. Fable 5.1 additionally declares structure_method = "instructor/anthropic_reasoning_tools", because it rejects the forced tool_choice that the backend's default instructor/anthropic_tools sends and structured output fails without it.
  • The GPT-5.6 series and GPT-6 Astra are served on OpenAI, Azure OpenAI, the Pipelex Gateway and Pipelex Manifold: gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna and gpt-6-astra are registered on the two direct backends and, through the remote config, on both hosted routing profiles. All four take text, images and PDF, produce text and structured output, and reason under thinking_mode = "manual" with a fixed temperature of 1. The Azure entries carry the dated deployment ids the hosted profiles also use as their wire model ids.

Changed

  • add-model skill follows the model's nearest sibling: the skill derives which backend TOMLs, test collection and deck entries a new model belongs in from the model it succeeds, instead of a fixed provider-to-backend table, and checks each backend actually serves the model. It takes the model's facts from the provider's own documentation with OpenRouter as a cross-check, hands the live tests to /test-model with a test class per declared capability, and adds the deck and changelog steps and make ugm once the gateway catalog carries the model.

Removed

  • The superseded GPT generations are retired from the rosters we ship (Breaking): the GPT-4.1 series, the o1, o3 and o4 reasoning models and the GPT-5, GPT-5.1 and GPT-5.2 generations are gone from azure_openai, from openai — which also loses gpt-3.5-turbo, gpt-4, gpt-4-turbo, the codex variants of those generations and the dated gpt-4o aliases — and from the gateway and manifold catalogs. o4-mini is retired from portkey in the same pass, since no other backend served it. None of them is unsupported: they are unlisted, and a project that still wants one keeps it by declaring it in its own backend config. What genuinely retires is their availability on the Pipelex Gateway and Pipelex Manifold, where the roster is ours. gpt-4o and gpt-4o-mini stay on both direct backends; the retired names that portkey and blackboxai still declare remain reachable through those, and openrouter's bulk third-party catalog is untouched.

Fixed

  • Claude Sonnet 5 is priced at its standard rate: claude-5-sonnet carried the $3 / $15 per million tokens it was announced at, but its $2 / $10 introductory rate became the standard price and the scheduled increase was cancelled. The entry is corrected on the Anthropic backend and in both hosted catalogs, so cost reporting and budget ceilings no longer overstate a Sonnet 5 run.
  • A failed publish can be recovered without damaging what already shipped: publish-pypi.yml scopes the signature upload to dist/*.sigstore.json so it no longer clobbers the wheel and sdist attached just before it, turns skip-existing on for a re-run or a manual dispatch, and refuses to touch a release whose tag names a commit other than the one being published. A retry no longer rebuilds the dists either: the build job asks PyPI what this version published and recovers those bytes from the first place that holds them — the build an earlier attempt of this run stored, an artifact an earlier run stored for the same commit, or the files PyPI itself serves — building fresh only when PyPI answers that nothing was published under this version. Whatever it holds is then checked to be one wheel and one source tarball of the version being released and, when PyPI serves that version, byte-for-byte what PyPI publishes, so the release assets are the bytes PyPI serves rather than a rebuild that probably matches them. The release is now tagged at the commit it ships, named explicitly with --target, rather than at the default branch's head.
  • A generated image is stored under its own media type, so a store no longer serves it as binary/octet-stream: GeneratedContentFactory.make_image_content resolves the effective mime type once and already used it to mint the storage key's extension, but passed no content_type to StorageProviderAbstract.store on either the direct-bytes path or the fetched-remote one. The S3 provider only sets ContentType when it is given one, so every generated image landed untyped and S3 answered binary/octet-stream on the way back out — which reached any consumer that trusts the stored type, a same-origin assets route serving the object to a browser among them. Both calls now pass the resolved mime type, so the key's extension, the object's stored type and the reported mime_type cannot diverge.
  • A generated image fetched from a remote URL is stored under the media type that URL served: GeneratedImageRawDetails admits a bare URL with no mime type and no image format on the promise that the type is settled when the bytes are downloaded, and nothing kept that promise — the fetch discarded the response's Content-Type and the resolution fell through to the requested image format or to a hardcoded image/jpeg. The new fetch_file_and_content_type_from_url_httpx reports the declared type alongside the bytes, normalized and with its parameters stripped, and the factory stores under any image/<subtype> it names — not merely the formats ImageFormat can itself produce, since what this runtime generates is a different question from what a remote URL may serve, and a GIF or an AVIF stored as image/jpeg is the very error being removed. The storage key's extension follows that subtype so it keeps agreeing with the stored type. A type the caller declared still wins, and a served type that is not an image at all — the text/html of an error page dressed as a 200 — is dropped.
  • A remote image that fails to download degrades to its URL instead of failing the pipe: make_image_content guarded its fetch with except (httpx.HTTPStatusError, httpx.RequestError), but fetch_file_from_url_httpx converts every httpx failure into RemoteFileFetchError, so that clause caught nothing and a 404 or a timeout on a remote image propagated out and failed the whole run. The guard now names the exception the fetch actually raises, and the fallback it was written for — log the warning, keep the remote URL — runs.
  • A remote fetch honours a timeout again: fetch_file_from_url_httpx passed its request_timeout straight to httpx, and httpx reads an explicit timeout=None — the parameter's own default — as no timeout at all rather than as its client default. Every caller that did not name one therefore had no timeout, so a hanging server blocked the caller indefinitely and the TimeoutException branch that raises a caller-facing RemoteFileFetchError was unreachable. The helper now passes httpx's USE_CLIENT_DEFAULT sentinel where no timeout was asked for.
  • A manifold error on the native routes keeps its request id under the gateway's pipelex-spelled trace header: extract_manifold_metadata reads the gateway's trace id from x-pipelex-trace-id before the inherited x-portkey-trace-id, still preferring a provider's own x-request-id over both. The gateway emits the two spellings with the same value today, so nothing changes yet; once it drops the vendor one, such an error whose provider sent no x-request-id keeps a request id instead of reporting none. extract_gateway_metadata is unchanged and still reads the vendor spelling alone — it serves the Portkey cloud and the manifold image path, which travels on portkey_ai and keeps that spelling until it is ported off the SDK.

What's Changed

  • feature/Manifold-trace-id-spelling · L-260918-a332cc by @lchoquel in #1213
  • feature/Refresh-add-model-skill · L-260919-74f437 by @lchoquel in #1217
  • feature/Add-models · L-260920-1feb2b by @lchoquel in #1218
  • feature/Generated-image-stored-untyped · L-260920-76086e by @lchoquel in #1220
  • feature/Publish-workflow-recovery · L-260827-8724d3 — sigstore upload clobbers dists by @lchoquel in #1222
  • feature/Roster-refresh · L-260920-6c3d2b by @lchoquel in #1219
  • feature/Dispatch-retry-rebuilds-dists · L-260920-487091 by @lchoquel in #1223
  • Release v0.61.0 by @lchoquel in #1224

Full Changelog: v0.60.0...v0.61.0