Skip to content

Releases

v0.11.13

Choose a tag to compare

@github-actions github-actions released this 08 Nov 06:07
1bd28cd

wiremux 0.11.13

Highlights

Messages requests that Anthropic rejected now use one message per role, with each tool result before any text.

A failed tool result is no longer sent as an ordinary success on Chat Completions, Responses, or Gemini.

Bug fixes

  • Chat Completions, Responses, and Gemini sent a failed tool result as a success. Those APIs have no field for a tool error. Encode now stops with hard-error at items[N].is_error: chat-completions has no tool error field (or responses, or gemini). send, stream_with_loss, the proxy, and wiremux map return that error instead of the success body. Messages still writes is_error. Converse still writes toolResult.status of error. A payload of {"ok":false} stays a success when is_error is false (#732).

  • Anthropic rejected two user messages or two assistant messages in a row. A parallel tool turn was one message per call or result, so the next Messages request failed before the model saw it. Encode now joins those turns into one message. That covers parallel calls, parallel results (a failure can sit beside a success), reasoning followed by a call or by text, and a decoded tool call plus text. Hosted tool items and unknown JSON are still copied through unchanged (#734).

  • Anthropic rejected a user message when text came before tool_result. The error is tool_use ids found without tool_result blocks immediately after. Messages encode writes every tool_result first, then any text, including when a later user turn is joined onto earlier text. A blank user turn does not insert "." when a tool result follows it. A user turn with no tool result still uses "." for empty text (#735).

  • Anthropic rejected a failed tool result whose content was empty. The error is content cannot be empty if is_error is true. Messages encode writes "." for that result. The loss log records empty error tool result became '.'. A successful tool result with no text stays empty, and is_error stays on the failed result (#736).

Upgrading

Set wiremux and wiremux-auth to 0.11.13. No public struct or enum field was added, so existing literals still compile.

Encoding is_error: true to Chat Completions, Responses, or Gemini now fails instead of producing the success body. Messages and Converse still encode that failure.

Full changelog

v0.11.12...v0.11.13

v0.11.12

Choose a tag to compare

@github-actions github-actions released this 07 Nov 23:03
6e8ce99

wiremux 0.11.12

Highlights

Tool JSON inside a cache breakpoint is sent, and a Gemini stream keeps each argument on the call that owns it.

A rate limit inside HTTP 200 comes back as HTTP 429, and a context-window stop is no longer a normal end.

Bug fixes

  • A cache breakpoint around a JSON tool result sent an empty string or a dot. Chat, Responses, Converse, and Messages now send that JSON. A second breakpoint, text beside the JSON, and FunctionOutput.output stay with it. Gemini already kept the JSON (#728).

  • Gemini stream argument bytes were appended to the only open call. A delta whose index is not open yet waits on that index, including a custom-tool delta. A later start at that index fills the name and keeps the bytes. Two open calls still keep their own arguments (#728).

  • A rate limit or server error inside HTTP 200 looked like a normal reply. Gemini code 429 or RESOURCE_EXHAUSTED is HTTP 429, and Chat error.type is rate_limit_exceeded. api_error, server_error, overloaded_error, numeric 503, and Gemini UNAVAILABLE are HTTP 503, the same transient server error the client already returns. A billing error, INVALID_ARGUMENT, and an invalid_request_error stay HTTP 400 (#730).

  • A rejected key or a missing model was classified from a nearby word. A bad-key phrase is HTTP 401 even when the numeric code is 5xx. Code 408 with a rate-limit phrase stays a rate limit. A numeric 4xx other than 408 and 429 wins over that phrase. model not found, no such model, models/<id> is not found, and JSON code 404 are a missing model. does not exist counts only when the text is about a model (#730).

  • A context-window stop encoded as a normal end. Chat writes length. Converse writes max_tokens. Gemini writes MAX_TOKENS. Responses writes incomplete on the stream event, on StreamEncoder::finish, and on complete JSON. Converse end_turn, Chat tool_calls, and stop_sequence encode as Responses completed (#730).

  • A malformed function call or a content filter became a tool stop. Messages content_filter encodes as refusal, including when a tool is open. Gemini malformed_function_call stays MALFORMED_FUNCTION_CALL even when the vendor token is empty. Chat writes content_filter. Converse writes content_filtered. Responses writes failed. A Responses status of cancelled stays cancelled. The spelling canceled encodes as cancelled (#730).

  • Bedrock rejected the next turn after tool_choice none. When the history already has a call or a result, toolConfig.tools stays and toolChoice is not set. A turn with no tool block still omits toolConfig (#730).

  • A Gemini tool result dropped fileData.fileUri. PDF and image file URIs round-trip on functionResponse.parts. An S3 document and a blank file URL are dropped and recorded, with S3 document has no Gemini slot or document url is empty (#730).

  • A Gemini part that was only thoughtSignature was dropped. That signature is sent back on the next request (#730).

  • Messages rejected a request that set both temperature and top_p. temperature is sent and top_p is dropped, because that API rejects the pair. top_p alone is still sent (#730).

  • A Responses assistant message sent image, audio, or file parts as user input. Those parts are dropped and recorded. Assistant text stays output_text. A user message still sends input_image (#730).

  • Chat tool audio was written into the tool text. The bytes are not sent. The loss log records no slot (#730).

  • A Messages web citation dropped encrypted_index and cited_text. Non-empty values are kept. Missing values still encode as empty strings on the way back to Messages (#730).

Upgrading

Set wiremux and wiremux-auth to 0.11.12. No public struct or enum field was added, so existing literals still compile.

A Responses context-window stop is incomplete. A cancelled turn stays cancelled. The proxy returns HTTP 429 for a rate limit that arrived as HTTP 200, and HTTP 503 for a server error in that body. Messages sends temperature and drops top_p when both are set.

Full changelog

v0.11.11...v0.11.12

v0.11.11

Choose a tag to compare

@github-actions github-actions released this 06 Nov 23:29
6f6cb8b

wiremux 0.11.11

Highlights

When a model calls two tools, each tool receives the arguments that belong to it.

A Chat tool result keeps its output when a cache breakpoint wraps an image or a document instead of text.

Bug fixes

  • Parallel tool calls mixed their arguments. When two calls were announced and the argument text arrived afterward, the first call was empty and both payloads were appended to the second call. Each argument stays on the call that owns it (#724).

  • A request that was only a system cache checkpoint encoded as an empty message list. Chat and Messages reject that request. Responses names the dropped checkpoint. Converse says the system block still needs a message turn. A Messages request with no items is still an empty list (#724).

  • A Chat tool result lost its output when a cache breakpoint wrapped an image, document, video, or search result. The original tool output is sent. Nested text still uses the text parts (#720).

  • A Responses tool result whose only part was JSON was sent as an empty string. The JSON text is sent. A later breakpoint that adds no parts no longer clears an image already kept on that result (#722).

  • Messages wrote "model": "" when the destination model was empty. The key is omitted on the complete body and on the stream start frame. A named destination model is still written (#722, #723).

Upgrading

Set wiremux and wiremux-auth to 0.11.11. No public struct or enum field was added, so existing literals still compile.

A caller that maps parallel tool calls now sees each argument on the call that owns it. A Messages request or stream with an empty destination model omits model instead of sending an empty string.

Full changelog

v0.11.10...v0.11.11

v0.11.10

Choose a tag to compare

@github-actions github-actions released this 06 Nov 16:54
010d39e

wiremux 0.11.10

Highlights

A tool result or system prompt wrapped in more than one cache breakpoint keeps its text.

Converse no longer puts a "." in front of tool text that sits inside a breakpoint.

Bug fixes

  • Chat and Gemini dropped tool text wrapped in two cache breakpoints. The text stays. Chat writes the outer breakpoint mode and records each inner mode as a drop. Gemini records every layer and still sends the tool text or inline image (#713).

  • Messages, Gemini, and Converse sent an empty system prompt when two cache breakpoints wrapped the text. The system text stays (#715).

  • Converse sent "." and then the real tool text when a cache breakpoint wrapped that text. The tool result is the text alone. A tool result that is actually empty still becomes "." (#716).

  • A Chat tool image inside a cache breakpoint disappeared with an empty loss log. The image is still omitted, because Chat tool messages have no image slot. The loss log records that drop and the breakpoint mode (#717).

Upgrading

Set wiremux and wiremux-auth to 0.11.10. No public struct or enum field was added, so existing literals still compile.

A caller that encoded nested cache breakpoints around tool text or a system prompt now sees that text on the wire. A Converse tool result no longer starts with a "." when the text was inside a breakpoint.

Full changelog

v0.11.9...v0.11.10

v0.11.9

Choose a tag to compare

@github-actions github-actions released this 24 Oct 04:48
96c45df

wiremux 0.11.9

Highlights

A token cap of 0 is now an error on Chat, Responses, and Gemini, the same as Messages and Converse.

Chat and Responses no longer crash when a cache breakpoint wraps thinking, or when two breakpoints wrap text.

Bug fixes

  • Chat, Responses, and Gemini sent a token cap of 0. max_tokens, max_completion_tokens, max_output_tokens, and generationConfig.maxOutputTokens of 0 are now the error max_tokens must be at least 1, and no request body is produced. An omitted cap stays omitted. A value of 1 is still sent (#708).

  • Chat and Responses crashed when a cache breakpoint wrapped thinking. Two nested breakpoints around text crashed the same way. Encode peels every breakpoint layer. Thinking is dropped the same way a top-level thinking part is dropped, and the text inside nested breakpoints is still sent (#709).

  • tokio 1.54.0 and ctutils 0.4.2 were still in the lockfile. Those crates are now 1.54.1 and 0.4.4 (RUSTSEC-2026-0384 and RUSTSEC-2026-0385) (#706).

Upgrading

Set wiremux and wiremux-auth to 0.11.9. No public struct or enum field was added, so existing literals still compile.

A caller that set max_tokens to 0 on Chat, Responses, or Gemini now gets MapError instead of a request body. Messages still fills an omitted cap with 4096. Chat, Responses, and Gemini still leave an omitted cap off the request.

Full changelog

v0.11.8...v0.11.9

v0.11.8

Choose a tag to compare

@github-actions github-actions released this 22 Oct 01:18
a29e63f

wiremux 0.11.8

Highlights

Image, audio, and document parts that are only whitespace are no longer sent. Responses include is written only when you set sampling.include.

Out-of-range temperature, top_p, Chat frequency and presence penalties, Messages and Converse max_tokens of 0, and Chat n of 0 are rejected before the request is sent.

Bug fixes

  • Responses always sent include: ["reasoning.encrypted_content"]. The field is omitted when sampling.include is empty. Other entries are written as you set them, and reasoning.encrypted_content is included only when that list already contains it (#687).

  • OpenAI still received fields those models reject. Chat omits stop on o3 and o4-mini, and omits logprobs on gpt-5, gpt-5-mini, and gpt-5-nano. gpt-5.1 and gpt-5.2 omit logprobs unless reasoning effort is none. Responses omits temperature, top_p, and top_logprobs under that same gpt-5 rule. Each omission is recorded as a drop (#688).

  • A system or developer content_parts list lost its text on Messages, Gemini, and Converse. Those wires now send the text parts from the list. Image, document, audio, and raw parts in that list are dropped and recorded (#688).

  • A Chat host never saw a Converse validation error. A cross-wire failure body that wiremux recognizes is rewritten into the caller's dialect, and the upstream status stays, including 5xx. Same-wire errors stay raw. An HTTP 200 vendor error still becomes 400 (#689).

  • Two different tool ids became one Messages tool id. Characters other than letters, digits, _, and - still become _, and a run of them is one _. A second id that lands on the same string gets _2, then _3. An id that already contains __ keeps both underscores (#690).

  • A Gemini tool image or tool text inside a cache breakpoint was dropped. The image and the text stay on the Gemini request. Other wires are unchanged (#691, #692).

  • A blank document file id was still sent. Chat, Responses, Messages, and Gemini do not send a document file id that is empty or only spaces (#693, #694).

  • A whitespace image URL was sent, and Gemini wrote [image: ]. A URL that is empty after trimming is omitted on Chat, Responses, Messages, and Gemini. A non-empty https URL is still the Gemini text placeholder (#695).

  • Blank image bytes, audio data, and document bytes were still uploaded. A payload that is empty after trimming is omitted, including a data URL whose base64 payload is only spaces. A non-empty payload is unchanged. Messages has no audio slot (#696).

  • An empty stop string was sent. Chat, Messages, Gemini, and Converse omit an empty stop entry and keep any remaining entry. A stop entry that is only spaces is still sent. Responses still has no stop field. o3 and o4-mini still omit stop for every entry (#697).

  • Messages sent max_tokens: 0. That value is now an error, max_tokens must be at least 1. An omitted max_tokens still becomes 4096, with the existing record that Messages requires max_tokens (#698).

  • Converse sent maxTokens: 0, and temperature or topP outside 0 to 1. max_tokens of 0 is an error. Temperature and top_p outside 0 to 1, including a value that is not finite, are errors (#699, #700).

  • Chat and Responses sent temperature above 2 and top_p above 1. When the field would be sent, temperature must be from 0 to 2 and top_p from 0 to 1. Messages uses 0 to 1 for both. gpt-5, gpt-5-mini, gpt-5-nano, and gpt-5.1 or gpt-5.2 with a reasoning effort other than none still omit those fields instead of returning this error (#701).

  • Chat sent frequency_penalty or presence_penalty outside -2 to 2. Those values are errors, including on models where temperature is omitted (#702).

  • Chat sent n: 0. That value is an error, n must be at least 1. n of 1 is still sent (#703).

  • Newer Claude models were sent a forced tool choice. For claude-opus-5-5, claude-sonnet-5-5, claude-fable-5-1, and claude-mythos-5-1, Messages tool and any are sent as auto, and the loss detail is model forces tool_choice auto. A dated suffix is the same family. A same-wire Messages client can put the original choice back with restore_same_wire_messages_tool_choice (#684).

  • rustls-webpki 0.103.15 still trusted emSign intermediates. The lockfile is now 0.103.16 (RUSTSEC-2026-0382) (#687).

Upgrading

Set wiremux and wiremux-auth to 0.11.8. No public struct or enum field was added, so existing literals still compile.

Encoded JSON omits the blank parts and rejected fields above, and out-of-range sampling returns MapError instead of a vendor status. A same-wire Messages caller that still needs tool or any on the Claude families listed above should call restore_same_wire_messages_tool_choice after encode.

Gemini still sends maxOutputTokens of 0. Chat still sends logit_bias, and it still sends n of 1 or greater. Gemini still sends frequency and presence penalties.

Full changelog

v0.11.7...v0.11.8

v0.11.7

Choose a tag to compare

@github-actions github-actions released this 19 Oct 18:57
8036af4

wiremux 0.11.7

Highlights

A same-wire Chat stream keeps the vendor error type and code. A model list that is only an error object uses the vendor message.

A response.failed frame that still has assistant text, a tool call, or audio returns that vendor error instead of the text.

Bug fixes

  • A Chat stream error stored the vendor code in error.type. When the client set stream to true and the upstream HTTP 200 body was only an error object, error.code disappeared. The event: error data is that JSON, so both fields stay. A non-stream request is HTTP 400 with the same JSON. A Responses stream still uses the flat error event, with message and code at the top (#683).

  • A model list error looked like an empty catalog. An error object with no data or models array now uses the vendor message. data: null without an error object is still the generic catalog error (#681).

  • response.failed returned assistant text and hid the vendor error. A frame with assistant text, a tool call, or audio, including a type-only frame, returns the vendor error. Encrypted reasoning and a hosted item with an id are still kept. The proxy returns the vendor error and does not forward that text as the assistant answer (#679).

  • The proxy example said every request path is ignored. It now names /count_tokens and :countTokens, and it says a same-wire Chat error object stays that JSON (#682).

Upgrading

Set wiremux and wiremux-auth to 0.11.7. Existing call sites do not need changes. A host that read error.type on a same-wire Chat stream error now sees the vendor type, not the code. A host that treated assistant text on response.failed as the answer now gets the vendor error when that text, a tool call, or audio is present.

Full changelog

v0.11.6...v0.11.7

v0.11.6

Choose a tag to compare

@github-actions github-actions released this 18 Oct 20:10
741b131

wiremux 0.11.6

Highlights

A streaming Responses failure keeps encrypted reasoning and a hosted tool payload instead of dropping them.

The proxy sends a header API key, including the shipped OpenRouter Codex profile, and a catalog ingest no longer leaves a partial write behind.

Bug fixes

  • A streaming response.failed frame dropped encrypted reasoning. The client returned please wait and no events, even when encrypted_content was set. That payload, and a hosted item that carries an id or other fields, is now delivered. Assistant text, a tool call, audio, or an empty shell on that frame still returns the vendor message (#672).

  • A non-JSON 200 looked like a JSON parse error. send and list_models now return a vendor error whose message is the page text. A stream that never becomes a frame uses that same vendor error (#672).

  • An error object hid encrypted reasoning and a hosted payload. Non-empty encrypted_content stays part of the answer, including on a failed response. An empty encrypted string does not. A hosted item with an id stays part of the answer. An empty message, empty output text, empty audio, and a hosted item that is only a type still return the vendor message (#669).

  • The proxy returned 401 for a header API key. auth status already showed a token for shipped openrouter-codex, and wiremux proxy stopped before the upstream call. The proxy now sends that Authorization or x-api-key header. A credentials file written after the proxy starts is used on the next request. If the token endpoint cannot be reached, the proxy returns 502 instead of 401. The 401 text names [oauth], access_env, [headers] Authorization or x-api-key, and auth_scheme = "none". auth login uses the same list (#673, #674).

  • Ingest left an earlier profile in place when a later write failed. Each profile is written to its own temp file first. Live files are replaced only after every temp write succeeds. A failed temp write removes those temps and leaves the existing profiles unchanged (#675).

Upgrading

Set wiremux and wiremux-auth to 0.11.6. Existing call sites do not need changes. A host that treated every Responses response.failed frame as an error now receives encrypted reasoning and hosted payloads when the frame carries them. A non-JSON HTTP 200 from send or list_models is a vendor error, not a JSON parse error.

Full changelog

v0.11.5...v0.11.6

v0.11.5

Choose a tag to compare

@github-actions github-actions released this 17 Oct 14:15
b84dcde

wiremux 0.11.5

Highlights

When a response has no text, refusal, audio, or named tool call, you get the vendor's message back.

The proxy returns that message as a client error instead of HTTP 502.

Bug fixes

  • A failed Responses body finished as failed and dropped the vendor error. decode_response returns the vendor message, such as please wait, when the body has no text, refusal, audio, or named tool call. A real leaf beside the error stays a completion. An SSE response.failed frame stays an error (#663).

  • The proxy treated an empty Responses output shell as a success. A cross-wire caller received HTTP 502 and the text decode upstream body:. The proxy now returns the vendor message as a client error (#665).

  • An empty Messages text or thinking block hid the vendor error. A blank string counted as a finished answer, so a cross-wire caller received HTTP 502. The proxy returns the vendor message. A non-empty string, a typed citation, or a thinking signature still counts as a completion (#666).

Upgrading

Set wiremux and wiremux-auth to 0.11.5. This release adds no public fields. Callers that treated an empty Responses output shell, or an empty Messages text or thinking block, as a finished answer now receive the vendor error.

Full changelog

v0.11.4...v0.11.5

v0.11.4

Choose a tag to compare

@github-actions github-actions released this 16 Oct 15:02
9bd333b

wiremux 0.11.4

Highlights

A Messages image that is only a file id stays on the next Messages request.

An empty part no longer hides a vendor error.

Bug fixes

  • An empty part hid the vendor error. Gemini, Converse, and Messages treated an empty part, an empty output block, or an empty tool or image block as a finished answer. The vendor error is returned. A named tool, image bytes, a file id, a file URI, and a nonempty stopReason still count as a completion (#660).

  • A Messages image that was only a file id disappeared on the next request. The text stayed and the picture did not. Same-wire Messages keeps source.type of file and source.file_id. A Responses request drops that image, and the loss line says Messages image file_id has no Responses slot (#661).

  • Chat image detail was dropped, and an empty image, audio clip, or tool call hid an error. detail low or high on a Chat data URL round-trips. auto stays omitted. Messages, Gemini, and Converse still receive the bytes and record the detail. An empty image_url, an empty input_audio, or tool_calls with an empty object no longer hides a vendor error (#658).

  • Tool-call arguments that arrived before the name left that call. Those fragments stay on the call. A stream that ends without an id or a name still releases them (#658).

  • Azure model lists requested the wrong URL. list_models GETs {base}/openai/models and keeps api-version from the chat path. A body with data[].id is the catalog. /openai/v1, /api/v3, Gemini, and Vertex URLs are unchanged (#658).

Upgrading

MSRV is still 1.95. Use 0.11.4 from crates.io.

No public struct or enum variant gained a field. A struct literal from 0.11.3 still compiles.

Same-wire Messages now keeps an image whose source type is file and whose file_id is set. A Responses body does not include that block. Decode of an empty Gemini part, an empty Converse output block, or an empty Messages tool or image block returns the vendor error instead of an empty success.

Full changelog

v0.11.3...v0.11.4