diff --git a/package.json b/package.json index 4b901342..7be70c9d 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.10.21", + "version": "2026.10.22", "type": "module", "packageManager": "pnpm@11.13.0", "scripts": { diff --git a/release-notes/2026.10.22.md b/release-notes/2026.10.22.md new file mode 100644 index 00000000..3278ee0b --- /dev/null +++ b/release-notes/2026.10.22.md @@ -0,0 +1,18 @@ +**Upgrade notes:** +- The bundled core is now 0.75.0. The control-plane protocol stays at 48, so remote servers on core 0.74.0 keep working. +- Nothing is cleared; the request history, stored payloads and settings carry over. +- Plugins: changes a hook makes to the request or tool call it receives now take effect without returning it. Before, they were dropped unless the hook returned the object. The two built-in plugins are updated unless their code was edited. + +**Security:** +- The dangerous-command check now looks at every choice of a streamed Chat Completions answer and every candidate of a Gemini answer, not only the first. An upstream could otherwise get a tool call past the check by placing it in a second choice, or by spreading its arguments across two choices. +- In a streamed answer with several choices, placeholders are restored in each choice separately; the choices could get mixed before. + +**Plugins:** +- Plugins have a global `tw` with helpers for common edits: `tw.appendSystem`, `tw.texts`, `tw.toolCalls`, `tw.mapStrings`, `tw.replace`, `tw.streamReplace`, `tw.lines` and `tw.pairs`. `tw.streamReplace` replaces text in streamed answers, including a match that spans two pieces of the stream. The template for a new plugin uses them. See the Plugins page of the documentation. +- A stream-mode plugin that held back text and cut a placeholder in two left the placeholder in the answer instead of the original value. This is fixed. +- A stream-mode plugin that failed and was skipped could lose or reorder the text it was holding. This is fixed. +- In answers with several choices, plugins keep each choice apart, and every choice of a non-streamed answer goes through them. +- A stream-mode plugin that only holds text back, without changing it, is no longer recorded as having changed the answer. + +**Other:** +- rustls 0.23.46 (RUSTSEC-2026-0346 to -0349). diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 3a0f23db..fe443e82 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.60.2", + "windows-sys 0.52.0", "wl-clipboard-rs", "x11rb", ] @@ -985,7 +985,7 @@ dependencies = [ "libc", "option-ext", "redox_users 0.5.3", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -1171,7 +1171,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -2661,7 +2661,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]] @@ -2996,7 +2996,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.45.0", ] [[package]] @@ -3625,7 +3625,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -3681,7 +3681,7 @@ dependencies = [ "security-framework", "security-framework-sys", "webpki-root-certs", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4809,7 +4809,7 @@ dependencies = [ "getrandom 0.4.3", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4832,7 +4832,7 @@ dependencies = [ [[package]] name = "thinkwatch-lite" -version = "2026.10.21" +version = "2026.10.22" dependencies = [ "anyhow", "block2", @@ -5335,8 +5335,8 @@ dependencies = [ [[package]] name = "tw-api" -version = "0.74.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.74.0#21e560cdfa0cb197d1688b329b18123547ce1d8f" +version = "0.75.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.75.0#f040a92a2d509d24c21e8a460e25f6cd3db2cd39" dependencies = [ "serde", "serde_json", @@ -5347,8 +5347,8 @@ dependencies = [ [[package]] name = "tw-dialect" -version = "0.74.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.74.0#21e560cdfa0cb197d1688b329b18123547ce1d8f" +version = "0.75.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.75.0#f040a92a2d509d24c21e8a460e25f6cd3db2cd39" dependencies = [ "memchr", "serde", @@ -5357,8 +5357,8 @@ dependencies = [ [[package]] name = "tw-guard" -version = "0.74.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.74.0#21e560cdfa0cb197d1688b329b18123547ce1d8f" +version = "0.75.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.75.0#f040a92a2d509d24c21e8a460e25f6cd3db2cd39" dependencies = [ "aho-corasick", "base64 0.22.1", @@ -5376,8 +5376,8 @@ dependencies = [ [[package]] name = "tw-link" -version = "0.74.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.74.0#21e560cdfa0cb197d1688b329b18123547ce1d8f" +version = "0.75.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.75.0#f040a92a2d509d24c21e8a460e25f6cd3db2cd39" dependencies = [ "serde", "serde_json", @@ -5403,8 +5403,8 @@ dependencies = [ [[package]] name = "tw-types" -version = "0.74.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.74.0#21e560cdfa0cb197d1688b329b18123547ce1d8f" +version = "0.75.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.75.0#f040a92a2d509d24c21e8a460e25f6cd3db2cd39" dependencies = [ "serde", "ts-rs", @@ -5412,8 +5412,8 @@ dependencies = [ [[package]] name = "tw-watch" -version = "0.74.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.74.0#21e560cdfa0cb197d1688b329b18123547ce1d8f" +version = "0.75.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.75.0#f040a92a2d509d24c21e8a460e25f6cd3db2cd39" dependencies = [ "libc", "notify", @@ -5423,8 +5423,8 @@ dependencies = [ [[package]] name = "tw-yaml" -version = "0.74.0" -source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.74.0#21e560cdfa0cb197d1688b329b18123547ce1d8f" +version = "0.75.0" +source = "git+https://github.com/ThinkWatchProject/ThinkWatch-Core.git?tag=v0.75.0#f040a92a2d509d24c21e8a460e25f6cd3db2cd39" dependencies = [ "saphyr-parser", "thiserror 2.0.21", @@ -5888,7 +5888,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 84641a32..0a269a20 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "thinkwatch-lite" -version = "2026.10.21" +version = "2026.10.22" edition = "2024" # **这个数决定依赖能升到哪一版。**edition 2024 的解析器只挑声明的 Rust # 版本编得动的依赖:写 1.85 的时候,`cargo update` 一直停在旧的 time 和 @@ -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.74.0" } -tw-types = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.74.0" } -tw-yaml = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.74.0" } -tw-guard = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.74.0" } -tw-watch = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.74.0" } -tw-link = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.74.0" } +tw-api = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.75.0" } +tw-types = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.75.0" } +tw-yaml = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.75.0" } +tw-guard = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.75.0" } +tw-watch = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.75.0" } +tw-link = { git = "https://github.com/ThinkWatchProject/ThinkWatch-Core.git", tag = "v0.75.0" } [lib] name = "thinkwatch_lite_lib" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index bf04a9c0..7843a828 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.10.21", + "version": "2026.10.22", "identifier": "app.thinkwatch.lite", "build": { "beforeDevCommand": "pnpm dev", diff --git a/src/plugins/Editor.i18n.ts b/src/plugins/Editor.i18n.ts index 87bc6d0d..7a2ee7c5 100644 --- a/src/plugins/Editor.i18n.ts +++ b/src/plugins/Editor.i18n.ts @@ -41,13 +41,11 @@ export const editorText = messages( ' settings: { note: { type: "string", label: "附加内容", value: "" } },', "};", "", - "// 请求发往上游之前调用:req.system 为系统提示词,ctx.settings 为设置项的值。", - "// 返回修改后的 req;返回 undefined 表示不修改。", + "// 请求发往上游之前调用:修改 req 即生效,ctx.settings 为设置项的值。", + "// tw 提供常用的改写函数,例如 tw.appendSystem 在系统提示词末尾附加一段文字。", "export function onRequest(req, ctx) {", ' const note = String(ctx.settings.note ?? "").trim();', - ' if (note === "" || req.system.includes(note)) return undefined;', - ' req.system = req.system ? req.system + "\\n\\n" + note : note;', - " return req;", + ' if (note !== "") tw.appendSystem(req, note);', "}", ]), @@ -117,14 +115,12 @@ export const editorText = messages( ' settings: { note: { type: "string", label: "Note", value: "" } },', "};", "", - "// Runs before a request goes to the upstream: req.system is the system prompt, and", - "// ctx.settings holds the values of the settings. Return the changed req, or undefined", - "// to leave the request unchanged.", + "// Runs before a request goes to the upstream: changes to req take effect, and", + "// ctx.settings holds the values of the settings. tw provides common edits, such as", + "// tw.appendSystem, which adds text to the end of the system prompt.", "export function onRequest(req, ctx) {", ' const note = String(ctx.settings.note ?? "").trim();', - ' if (note === "" || req.system.includes(note)) return undefined;', - ' req.system = req.system ? req.system + "\\n\\n" + note : note;', - " return req;", + ' if (note !== "") tw.appendSystem(req, note);', "}", ]),