From 8f7a10843b9616b0ccefc98061153fc629dfdbb1 Mon Sep 17 00:00:00 2001 From: fylorn <249551762+fylorn@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:28:34 +0800 Subject: [PATCH 1/2] Use core v0.57.1: requests other than POST are answered by the gateway Core 0.57.1 answers a request other than POST with a 404 instead of sending it to an upstream as an empty POST. Hermes Agent's start-up checks for a local model server (GET /api/tags, /version, ...) are therefore no longer forwarded or recorded, so the adoption note saying they appear in Traffic as failed requests is removed (code adopt.cost.hermes_agent.probes, its translation and the screenshot mock). The new core code gw.method.not_forwarded gets its Chinese sentence. The control-plane protocol (31) and the request store schema (23) are unchanged. Co-Authored-By: Claude Opus 5.5 --- scripts/shots/mock/clients.ts | 4 --- src-tauri/Cargo.lock | 44 ++++++++++++------------ src-tauri/Cargo.toml | 12 +++---- src-tauri/crates/tw-adopt/src/clients.rs | 7 ++-- src-tauri/msg-codes.txt | 1 - src/i18n/core.zh.json | 2 +- 6 files changed, 31 insertions(+), 39 deletions(-) diff --git a/scripts/shots/mock/clients.ts b/scripts/shots/mock/clients.ts index 476074b..8c49a39 100644 --- a/scripts/shots/mock/clients.ts +++ b/scripts/shots/mock/clients.ts @@ -419,10 +419,6 @@ function clientsNow(): DetectedClient[] { "adopt.cost.hermes_agent.restart", "Hermes Agent sessions that are already open keep their provider until they are restarted; the messaging gateway picks up the change with the next message.", ), - msg( - "adopt.cost.hermes_agent.probes", - "Hermes Agent checks whether the gateway is a local model server such as LM Studio or Ollama; those checks appear in Traffic as failed requests.", - ), ], }), ]; diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 8a14811..6a3d7a8 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -82,7 +82,7 @@ dependencies = [ "objc2-foundation", "parking_lot", "percent-encoding", - "windows-sys 0.52.0", + "windows-sys 0.59.0", "wl-clipboard-rs", "x11rb", ] @@ -974,7 +974,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.3", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1175,7 +1175,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2651,7 +2651,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -3591,7 +3591,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3647,7 +3647,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4733,7 +4733,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5279,8 +5279,8 @@ dependencies = [ [[package]] name = "tw-api" -version = "0.57.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.0#6dbc5bb1be9f24cc60ce2736781deb76f7b86529" +version = "0.57.1" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.1#2c0c9f343f317b81de2abd253c848b0f4e5c61f9" dependencies = [ "serde", "serde_json", @@ -5290,8 +5290,8 @@ dependencies = [ [[package]] name = "tw-dialect" -version = "0.57.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.0#6dbc5bb1be9f24cc60ce2736781deb76f7b86529" +version = "0.57.1" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.1#2c0c9f343f317b81de2abd253c848b0f4e5c61f9" dependencies = [ "serde", "serde_json", @@ -5299,8 +5299,8 @@ dependencies = [ [[package]] name = "tw-guard" -version = "0.57.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.0#6dbc5bb1be9f24cc60ce2736781deb76f7b86529" +version = "0.57.1" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.1#2c0c9f343f317b81de2abd253c848b0f4e5c61f9" dependencies = [ "base64 0.22.1", "regex", @@ -5313,8 +5313,8 @@ dependencies = [ [[package]] name = "tw-link" -version = "0.57.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.0#6dbc5bb1be9f24cc60ce2736781deb76f7b86529" +version = "0.57.1" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.1#2c0c9f343f317b81de2abd253c848b0f4e5c61f9" dependencies = [ "serde", "serde_json", @@ -5340,8 +5340,8 @@ dependencies = [ [[package]] name = "tw-types" -version = "0.57.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.0#6dbc5bb1be9f24cc60ce2736781deb76f7b86529" +version = "0.57.1" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.1#2c0c9f343f317b81de2abd253c848b0f4e5c61f9" dependencies = [ "serde", "ts-rs", @@ -5349,8 +5349,8 @@ dependencies = [ [[package]] name = "tw-watch" -version = "0.57.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.0#6dbc5bb1be9f24cc60ce2736781deb76f7b86529" +version = "0.57.1" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.1#2c0c9f343f317b81de2abd253c848b0f4e5c61f9" dependencies = [ "notify", "thiserror 2.0.21", @@ -5359,8 +5359,8 @@ dependencies = [ [[package]] name = "tw-yaml" -version = "0.57.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.0#6dbc5bb1be9f24cc60ce2736781deb76f7b86529" +version = "0.57.1" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.57.1#2c0c9f343f317b81de2abd253c848b0f4e5c61f9" dependencies = [ "saphyr-parser", "thiserror 2.0.21", @@ -5857,7 +5857,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 8f5a7c4..ec27b2e 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -26,12 +26,12 @@ license = "MIT" # twcore 二进制必须和这里编译进去的协议镜像来自同一个 core 版本 —— 打包脚本正是 # 从 tw-api 锁到的 tag 去取二进制的(见 scripts/fetch-core.sh)。 [workspace.dependencies] -tw-api = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.0" } -tw-types = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.0" } -tw-yaml = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.0" } -tw-guard = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.0" } -tw-watch = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.0" } -tw-link = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.0" } +tw-api = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.1" } +tw-types = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.1" } +tw-yaml = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.1" } +tw-guard = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.1" } +tw-watch = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.1" } +tw-link = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.57.1" } [lib] name = "thinkwatch_lite_lib" diff --git a/src-tauri/crates/tw-adopt/src/clients.rs b/src-tauri/crates/tw-adopt/src/clients.rs index e545c10..ea1dafa 100644 --- a/src-tauri/crates/tw-adopt/src/clients.rs +++ b/src-tauri/crates/tw-adopt/src/clients.rs @@ -666,11 +666,8 @@ pub fn adoptable() -> Vec { code!("adopt.cost.hermes_agent.restart"), "Hermes Agent sessions that are already open keep their provider until they are restarted; the messaging gateway picks up the change with the next message.", ), - // 指向本机的地址,它会挨个问几个本地模型服务的路径,网关把这些请求转给上游 - ( - code!("adopt.cost.hermes_agent.probes"), - "Hermes Agent checks whether the gateway is a local model server such as LM Studio or Ollama; those checks appear in Traffic as failed requests.", - ), + // 它起来时还会拿 GET 问几个本机模型服务的路径(`/api/tags`、`/version` …),看网关 + // 是不是 Ollama、LM Studio:core 0.57.1 起网关就地回 404,不转发、不记录,用不着说 ], verified: Verified::FieldsOnly, marker: &[crate::paths::HERMES_DIR], diff --git a/src-tauri/msg-codes.txt b/src-tauri/msg-codes.txt index c2023db..6356a4f 100644 --- a/src-tauri/msg-codes.txt +++ b/src-tauri/msg-codes.txt @@ -25,7 +25,6 @@ adopt.cost.dsh.web_search adopt.cost.grok_build.builtin_models adopt.cost.grok_build.campaigns adopt.cost.grok_build.helper_models -adopt.cost.hermes_agent.probes adopt.cost.hermes_agent.restart adopt.cost.omp.default_model adopt.cost.opencode.restart diff --git a/src/i18n/core.zh.json b/src/i18n/core.zh.json index c379cc7..50adb51 100644 --- a/src/i18n/core.zh.json +++ b/src/i18n/core.zh.json @@ -334,6 +334,7 @@ "gw.convert.tool_unsendable": "请求要求使用工具 {tool},但无法按上游「{upstream}」的格式发送。网页搜索这类服务端工具只能由所属的服务商执行。", "gw.convert.tools_unsendable": "请求要求调用工具,但其中的工具都无法按上游「{upstream}」的格式发送。网页搜索这类服务端工具只能由所属的服务商执行。", "gw.files.unsupported": "网关不托管文件,图片和文档请直接放在请求中发送。", + "gw.method.not_forwarded": "{method} {path} 不是 API 调用。网关只向上游转发 POST 请求。", "gw.request.body_too_large": "请求体大小为 {size} 字节,超过上限 {max} 字节。", "gw.upstream.timeout": "上游响应超时。", "gw.upstream.unreachable": "无法连接上游 {url},请检查接口地址、网络和代理设置。", @@ -663,7 +664,6 @@ "adopt.cost.qwen_code.other_models": "为快速回复、视觉、上下文压缩等任务单独设置的模型仍使用各自的提供方。", "adopt.cost.qwen_code.proxy": "Qwen Code 使用代理时,需将网关地址加入 NO_PROXY,否则发往网关的请求也会经过代理。", "adopt.cost.hermes_agent.restart": "已打开的 Hermes Agent 会话在重新启动前仍使用原来的提供方;消息网关从下一条消息起使用新配置。", - "adopt.cost.hermes_agent.probes": "Hermes Agent 会检测网关是否为 LM Studio、Ollama 等本机模型服务,这些检测请求会以失败请求的形式出现在流量中。", "// ── adopt.diag:接管为什么没生效 ────────────────────────────────": "", "adopt.diag.not_running": "{client} 当前未运行", "adopt.diag.not_running.detail": "下次启动时将读取新配置。", From 82294ad98776a3b2693d5390f8f6e89174b2834d Mon Sep 17 00:00:00 2001 From: fylorn <249551762+fylorn@users.noreply.github.com> Date: Fri, 2 Oct 2026 00:31:26 +0800 Subject: [PATCH 2/2] chore: 2026.10.0 Version bump in the four files and release-notes/2026.10.0.md for the release page. Co-Authored-By: Claude Opus 5.5 --- package.json | 2 +- release-notes/2026.10.0.md | 47 ++++++++++++++++++++++++++++++++++++++ src-tauri/Cargo.lock | 2 +- src-tauri/Cargo.toml | 2 +- src-tauri/tauri.conf.json | 2 +- 5 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 release-notes/2026.10.0.md diff --git a/package.json b/package.json index 86e7a16..082724e 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "thinkwatch-lite", "private": true, "description": "Desktop app for a local AI API gateway on macOS, Windows and Linux", - "version": "2026.9.26", + "version": "2026.10.0", "type": "module", "packageManager": "pnpm@11.13.0", "scripts": { diff --git a/release-notes/2026.10.0.md b/release-notes/2026.10.0.md new file mode 100644 index 0000000..6ba83f0 --- /dev/null +++ b/release-notes/2026.10.0.md @@ -0,0 +1,47 @@ +**Upgrade notes:** +- The bundled core is now 0.57.1, which speaks control-plane protocol 31. A remote server has to run core 0.57.x too: this version does not connect to 0.56.x, and 2026.9.26 and earlier do not connect to 0.57.x. +- **Request history is cleared** on the first start, as the request store is rebuilt. Configuration, keys and upstreams are kept. +- Two redaction rules are on by default: Chinese resident ID numbers and bank card numbers. In Observe, the factory mode, they are only recorded; in Enforce they are replaced before a request leaves. Either can be switched off on the Security page. +- Routing rules on input tokens now use the gateway's token-count estimate: one token per CJK character and 1,600 per image or file, with thinking left out. A request with many images can now cross a size threshold it used to stay under. + +**Searching the whole history:** +- The Traffic page used to search only the latest 2,000 requests it had loaded. A search or filter now also runs over every stored request, newest first. The footer says how far back the search has got, and **Search further** goes back another page. +- The toggle inside the search box also searches content. It covers what each request newly sent (the last user turn, tool results included) and its answer (text and tool calls), for requests whose payloads are still kept. +- Each content match shows an excerpt under the request, with credentials masked. + +**Upstream check-up:** +- **Upstreams › Check-up** compares each upstream with the others over 24 hours, 7 days, 30 days or a custom range: + - requests and failure rate; + - whether the model named in its answers matches the one sent, with the pairs that differ; + - the input it reports, as a multiple of the local estimate, against other upstreams serving the same model; + - the share of input read from the prompt cache in follow-up turns, against those upstreams too; + - median time to first token and generation speed. +- Every figure comes with its sample size. A deviation is marked only when both sides have enough samples: + - input: a gap of 25% or more, and only on the upstream further from the local estimate; + - cache: other upstreams read at least 30% from the cache and this one less than half of that. + +**ID and bank card numbers:** +- Outbound redaction now also replaces Chinese resident ID numbers and bank card numbers. A number counts only when its structure and check digit are valid: + - an ID number needs a region code, a real birth date and a valid check character; + - a card number needs the prefix and length of UnionPay, Visa, Mastercard, American Express, JCB, Discover or Diners Club, and must pass the Luhn check. +- Placeholders say what was there, such as `<>`, and the security log shows only the last four characters. + +**More clients:** +- The Clients page now connects Pi, oh-my-pi, Grok Build, Qwen Code and Hermes Agent: + - **Pi and oh-my-pi** get a provider of their own with the models the key can use. Their default model stays as it is, and ThinkWatch models are chosen in `/model`. + - **Grok Build** gets one model entry per gateway model, each with its own key, so the xAI session token is never sent to the gateway. One of them becomes the default model. Remote campaigns, which can change the default model, are turned off while it is connected. + - **Qwen Code** 0.19.3 or later gets a provider of its own in the OpenAI format, and the change applies after a restart. + - **Hermes Agent**: its default profile is pointed at the gateway, and other profiles keep their own configuration. +- **DeepSeek Harness** counts as installed when only its desktop app is. Models used through a DeepSeek account in the desktop app still go to DeepSeek directly, which the plan now says. +- The MCP page lists the servers of the five new clients without writing to them. Skills in the shared `~/.agents/skills` folder appear under a shared folder, and Cursor's hooks are scanned too. +- Codex stopped reading `OPENAI_BASE_URL` in April 2026, so a shell that still exports it is no longer reported as overriding the connection. + +**Getting started:** +- Until the first request reaches an upstream, the Overview page shows a checklist: add an upstream, connect a client, send a first request. +- Other pages show a hint for the next step where it applies. A hint can be hidden, and **Settings › General** shows the hidden ones again. + +**Requests other than POST:** +- These now get a 404 from the gateway itself. Hermes Agent sends such GETs when it starts, to tell whether a server is Ollama or LM Studio. +- They used to be sent to an upstream as empty POSTs and recorded as failed requests. + +The [Features](https://thinkwat.ch/docs/lite/features) page describes each of these in full. diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 6a3d7a8..9ffdbba 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -4756,7 +4756,7 @@ dependencies = [ [[package]] name = "thinkwatch-lite" -version = "2026.9.26" +version = "2026.10.0" dependencies = [ "anyhow", "block2", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ec27b2e..7ea1d7b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "thinkwatch-lite" -version = "2026.9.26" +version = "2026.10.0" edition = "2024" # **这个数决定依赖能升到哪一版。**edition 2024 的解析器只挑声明的 Rust # 版本编得动的依赖:写 1.85 的时候,`cargo update` 一直停在旧的 time 和 diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 3b54a34..65e4560 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "ThinkWatch Lite", - "version": "2026.9.26", + "version": "2026.10.0", "identifier": "app.thinkwatch.lite", "build": { "beforeDevCommand": "pnpm dev",