From 5824606b7650c65b1659871e854e8b74da403b82 Mon Sep 17 00:00:00 2001 From: fylorn <249551762+fylorn@users.noreply.github.com> Date: Fri, 9 Oct 2026 21:05:45 +0800 Subject: [PATCH] chore: v0.67.0 Co-Authored-By: Claude Opus 5.5 --- Cargo.lock | 38 +++++++++++++++++++------------------- Cargo.toml | 2 +- release-notes/0.67.0.md | 29 +++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 release-notes/0.67.0.md diff --git a/Cargo.lock b/Cargo.lock index d3da1b79..e034b726 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3143,7 +3143,7 @@ dependencies = [ [[package]] name = "tw-api" -version = "0.66.0" +version = "0.67.0" dependencies = [ "serde", "serde_json", @@ -3154,7 +3154,7 @@ dependencies = [ [[package]] name = "tw-bedrock" -version = "0.66.0" +version = "0.67.0" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -3175,7 +3175,7 @@ dependencies = [ [[package]] name = "tw-breaker" -version = "0.66.0" +version = "0.67.0" dependencies = [ "serde", "serde_json", @@ -3183,7 +3183,7 @@ dependencies = [ [[package]] name = "tw-config" -version = "0.66.0" +version = "0.67.0" dependencies = [ "blake3", "libc", @@ -3208,7 +3208,7 @@ dependencies = [ [[package]] name = "tw-control" -version = "0.66.0" +version = "0.67.0" dependencies = [ "axum", "base64", @@ -3250,7 +3250,7 @@ dependencies = [ [[package]] name = "tw-dialect" -version = "0.66.0" +version = "0.67.0" dependencies = [ "memchr", "serde", @@ -3259,7 +3259,7 @@ dependencies = [ [[package]] name = "tw-engine" -version = "0.66.0" +version = "0.67.0" dependencies = [ "serde", "serde_json", @@ -3272,7 +3272,7 @@ dependencies = [ [[package]] name = "tw-gateway" -version = "0.66.0" +version = "0.67.0" dependencies = [ "arc-swap", "async-stream", @@ -3322,7 +3322,7 @@ dependencies = [ [[package]] name = "tw-guard" -version = "0.66.0" +version = "0.67.0" dependencies = [ "base64", "bytes", @@ -3338,7 +3338,7 @@ dependencies = [ [[package]] name = "tw-link" -version = "0.66.0" +version = "0.67.0" dependencies = [ "serde", "serde_json", @@ -3352,7 +3352,7 @@ dependencies = [ [[package]] name = "tw-observe" -version = "0.66.0" +version = "0.67.0" dependencies = [ "tokio", "tracing", @@ -3361,7 +3361,7 @@ dependencies = [ [[package]] name = "tw-plugin" -version = "0.66.0" +version = "0.67.0" dependencies = [ "libc", "rand 0.10.2", @@ -3376,7 +3376,7 @@ dependencies = [ [[package]] name = "tw-pricing" -version = "0.66.0" +version = "0.67.0" dependencies = [ "arc-swap", "flate2", @@ -3389,14 +3389,14 @@ dependencies = [ [[package]] name = "tw-secret" -version = "0.66.0" +version = "0.67.0" dependencies = [ "thiserror", ] [[package]] name = "tw-store" -version = "0.66.0" +version = "0.67.0" dependencies = [ "blake3", "bytes", @@ -3416,7 +3416,7 @@ dependencies = [ [[package]] name = "tw-types" -version = "0.66.0" +version = "0.67.0" dependencies = [ "serde", "serde_json", @@ -3425,7 +3425,7 @@ dependencies = [ [[package]] name = "tw-watch" -version = "0.66.0" +version = "0.67.0" dependencies = [ "libc", "notify", @@ -3436,7 +3436,7 @@ dependencies = [ [[package]] name = "tw-yaml" -version = "0.66.0" +version = "0.67.0" dependencies = [ "saphyr-parser", "serde_yaml_ng", @@ -3446,7 +3446,7 @@ dependencies = [ [[package]] name = "twcore" -version = "0.66.0" +version = "0.67.0" dependencies = [ "anyhow", "axum", diff --git a/Cargo.toml b/Cargo.toml index af40f736..546b1a97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,7 @@ categories = ["network-programming", "web-programming::http-server"] # 二进制走 CalVer,crate 走 SemVer —— 两者是两回事,卖给不同的人。 # 这里是 crate 的版本。 -version = "0.66.0" +version = "0.67.0" [workspace.dependencies] # ── 内部 crate ─────────────────────────────────────────── diff --git a/release-notes/0.67.0.md b/release-notes/0.67.0.md new file mode 100644 index 00000000..ea46c8f5 --- /dev/null +++ b/release-notes/0.67.0.md @@ -0,0 +1,29 @@ +This release stops requests from hanging on an upstream that answers and then goes quiet, lets a running request or a whole session be aborted, and makes Codex work through routes that convert its requests to another format: its tools, history, compactions and mid-conversation instructions now all arrive. Requests converted for Claude now use prompt caching. Signing in to a ChatGPT account on another device works again. + +**Upgrade notes** + +- The control-plane protocol version (`CONTROL_API_VERSION`) goes from 42 to 43. ThinkWatch Lite connects only to a core with the same protocol version: ThinkWatch Lite 2026.10.10 includes 0.66.0 (protocol 42) and does not connect to 0.67.0. A server used with it stays on 0.66.0 until the app is updated to a release that includes 0.67.0; `sudo twcore upgrade --version 0.66.0 --restart` switches a server back. +- **The request store's schema goes to 26: the request history and stored payloads are cleared on the first start.** Recorded attempts could hold an outcome that no longer exists. +- **`failover.next_on_slow_start` and `failover.stream_start_wait_secs` are removed.** A configuration that still has either fails to load and core starts in safe mode; the safe-mode repair offers to delete them. The new `failover.idle_timeout_secs` (default 300) replaces them. +- **Requests converted for Claude are cached.** Prompt-cache writes are billed at the provider's cache-write rate (25% above input for Anthropic) and reads at its cache-read rate (a tenth of input), and both are recorded and priced from the price table. Clients that mark their own breakpoints, such as Claude Code, are unchanged. +- Changed in the protocol: + - New endpoints `POST /request/{id}/abort` and `POST /sessions/{id}/abort` (→ `Aborted { requests }`). + - Attempts gain the outcomes `idle_timeout` (with the time waited) and `aborted`; a request aborted by the user is recorded with the failure source `aborted`. + - `FailoverView` gains `idle_timeout_secs` and loses `next_on_slow_start` and `stream_start_wait_secs`; the `slow_start` outcome is gone. +- Message codes, compared with 0.66.0: + - New: `gw.upstream.idle_timeout`, `gw.upstream.idle_timeout_mid_stream`, `gw.request.aborted`, `control.request_not_running`, `control.session_not_running`. + - Removed: `gw.slow_start`, `config.slow_start_too_short`. + +**No response.** An upstream that accepts a request and then sends nothing used to keep it forever: there is deliberately no overall timeout, and the only check, moving on when a stream was slow to start, was off by default and never applied to the last upstream. Now, when `failover.idle_timeout_secs` (300 seconds by default, 30 to 3600) pass without any content — text, reasoning or a tool call; keep-alive pings do not count — the gateway gives up on that upstream. Before anything has reached the client, the request moves to the next upstream and the silent one counts as a failure for its pause; when none is left, the client gets a timeout error in its own format instead of waiting. After content has started, the answer ends with an error event the client understands. A whole (non-streamed) answer counts the same time until it arrives. A streamed answer is held for at most 15 seconds; after that the client receives its response headers and keep-alive comments, so it does not give up while the gateway is still able to move to the next upstream. + +**Abort.** A running request, or every running request of a session, can be aborted from the control plane. The upstream call is dropped at once, the client gets an error, the request is recorded as aborted by the user, and the upstream is not set aside. + +**Codex through converted routes.** +- For some models Codex sends no top-level `tools` and declares every tool in an `additional_tools` input item. Those items were dropped, so a route converting to Anthropic, Chat, Gemini or Bedrock sent no tools at all, and Codex reported that it could not read files or run commands. Every tool now arrives, and tool calls come back to Codex under the names and kinds it declared. +- Local shell calls, tool search, mid-session reasoning-effort changes and agent messages in the history are converted instead of dropped. `text.verbosity` reaches GPT-5 and later models on Chat upstreams. +- Compacting a long session works on converted routes: the upstream writes a handoff summary, Codex receives it as its compaction, and later requests carry it back. OpenAI's own encrypted compactions still cannot be read by other upstreams and are refused clearly. +- Developer messages that arrive in the middle of a conversation stay where they are instead of joining the system prompt, so the system prompt stays the same from turn to turn and caching keeps working. + +**Prompt caching for Claude.** A request converted for Claude from a client that marks no cache breakpoints — Codex, Chat and Gemini clients — now gets them on the tools, the system prompt and the last two user turns, so each turn reads what the previous one cached. This applies to Anthropic-format upstreams and to Claude models on Bedrock. + +**ChatGPT account on another device.** OpenAI's device-code answer now gives its polling interval as text (`"5"`), which stopped the sign-in with "could not be read". Numbers written as text are now accepted there and in the other sign-in answers that carry durations.