fix(prompts): prioritize user language for reasoning (#1137)

This commit is contained in:
Hunter Bown
2026-05-07 23:53:15 -05:00
committed by GitHub
parent b31b93aaae
commit f283e56bd1
20 changed files with 98 additions and 64 deletions
+8
View File
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.8.20] - 2026-05-08
### Fixed
- **Chinese reasoning stays Chinese** - restore the #588 language contract after
the deterministic environment prompt regressed it. The latest user message now
chooses the natural language for both `reasoning_content` and the final reply;
the resolved `lang` field is only a fallback when the user turn is ambiguous.
## [0.8.19] - 2026-05-08
### Fixed
Generated
+14 -14
View File
@@ -1152,7 +1152,7 @@ dependencies = [
[[package]]
name = "deepseek-agent"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"deepseek-config",
"serde",
@@ -1160,7 +1160,7 @@ dependencies = [
[[package]]
name = "deepseek-app-server"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"anyhow",
"axum",
@@ -1182,7 +1182,7 @@ dependencies = [
[[package]]
name = "deepseek-config"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"anyhow",
"deepseek-secrets",
@@ -1194,7 +1194,7 @@ dependencies = [
[[package]]
name = "deepseek-core"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"anyhow",
"chrono",
@@ -1212,7 +1212,7 @@ dependencies = [
[[package]]
name = "deepseek-execpolicy"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"anyhow",
"deepseek-protocol",
@@ -1221,7 +1221,7 @@ dependencies = [
[[package]]
name = "deepseek-hooks"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"anyhow",
"async-trait",
@@ -1235,7 +1235,7 @@ dependencies = [
[[package]]
name = "deepseek-mcp"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"anyhow",
"serde",
@@ -1244,7 +1244,7 @@ dependencies = [
[[package]]
name = "deepseek-protocol"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"serde",
"serde_json",
@@ -1252,7 +1252,7 @@ dependencies = [
[[package]]
name = "deepseek-secrets"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"dirs",
"keyring",
@@ -1265,7 +1265,7 @@ dependencies = [
[[package]]
name = "deepseek-state"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"anyhow",
"chrono",
@@ -1277,7 +1277,7 @@ dependencies = [
[[package]]
name = "deepseek-tools"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"anyhow",
"async-trait",
@@ -1290,7 +1290,7 @@ dependencies = [
[[package]]
name = "deepseek-tui"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"anyhow",
"arboard",
@@ -1351,7 +1351,7 @@ dependencies = [
[[package]]
name = "deepseek-tui-cli"
version = "0.8.19"
version = "0.8.20"
dependencies = [
"anyhow",
"chrono",
@@ -1375,7 +1375,7 @@ dependencies = [
[[package]]
name = "deepseek-tui-core"
version = "0.8.19"
version = "0.8.20"
[[package]]
name = "deranged"
+1 -1
View File
@@ -19,7 +19,7 @@ default-members = ["crates/cli", "crates/app-server", "crates/tui"]
resolver = "2"
[workspace.package]
version = "0.8.19"
version = "0.8.20"
edition = "2024"
# Rust 1.88 stabilized `let_chains` in `if`/`while` conditions, which the
# codebase relies on extensively. Cargo enforces this so users on older
+7 -4
View File
@@ -225,12 +225,15 @@ deepseek --provider ollama --model deepseek-coder:1.3b
---
## What's New In v0.8.19
## What's New In v0.8.20
A hotfix release for DeepSeek endpoint defaults, plus the v0.8.18
TUI/runtime/install polish.
A hotfix release for Chinese reasoning language, DeepSeek endpoint defaults,
and the v0.8.18 TUI/runtime/install polish.
[Full changelog](CHANGELOG.md).
- **Chinese reasoning stays Chinese** - when the latest user message is in
Simplified Chinese, V4 `reasoning_content` and the final reply are prompted
to stay in Simplified Chinese even on an English system locale.
- **DeepSeek beta endpoint stays default worldwide** - Chinese locales and
legacy `deepseek-cn` configs now use `https://api.deepseek.com/beta`, so
strict tool mode and other beta-gated features remain available.
@@ -371,7 +374,7 @@ Key environment variables:
| `NO_ANIMATIONS=1` | Force accessibility mode at startup |
| `SSL_CERT_FILE` | Custom CA bundle for corporate proxies |
Set `locale` in `settings.toml`, use `/config locale zh-Hans`, or rely on `LC_ALL`/`LANG` to choose UI chrome and the default natural language sent to V4 models. See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) and [docs/MCP.md](docs/MCP.md).
Set `locale` in `settings.toml`, use `/config locale zh-Hans`, or rely on `LC_ALL`/`LANG` to choose UI chrome and the fallback language sent to V4 models. The latest user message still wins for natural-language reasoning and replies, so Chinese user turns stay Chinese even on an English system locale. See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) and [docs/MCP.md](docs/MCP.md).
---
+5 -3
View File
@@ -192,10 +192,12 @@ deepseek --provider ollama --model deepseek-coder:1.3b
---
## v0.8.18 新功能
## v0.8.20 新功能
面向 TUI、运行时和安装体验的跟进版本。[完整更新日志](CHANGELOG.md)。
面向中文思考语言、端点默认值、TUI、运行时和安装体验的热修复版本。[完整更新日志](CHANGELOG.md)。
- **中文思考保持中文** —— 当最新用户消息是简体中文时,即使系统 locale
是英文,V4 的 `reasoning_content` 和最终回复也会被提示保持简体中文。
- **直接运行 `deepseek` 会启动新会话** —— 同一目录开第二个终端时,不再静默进入
同一个中断检查点;需要恢复时请显式使用 `deepseek --continue`
- **Docker 成为受支持安装方式** —— 发布流程会推送
@@ -288,7 +290,7 @@ deepseek update # 检查并应用二进制更新
| `NO_ANIMATIONS=1` | 启动时强制无障碍模式 |
| `SSL_CERT_FILE` | 企业代理的自定义 CA 包 |
UI 语言与模型输出语言相互独立——`config.toml` 中设置 `locale`、使用 `/config locale zh-Hans`、或依赖 `LC_ALL`/`LANG`。详见 [docs/LOCALIZATION.md](docs/LOCALIZATION.md) 和 [docs/CONFIGURATION.md](docs/CONFIGURATION.md)。
`locale` 会控制界面语言,并作为模型自然语言的兜底设置;最新用户消息的语言优先级更高。也就是说,即使系统 locale 是英文,用户用中文提问时,V4 的 `reasoning_content` 和最终回复也应该使用中文。可`config.toml` 中设置 `locale`、使用 `/config locale zh-Hans`、或依赖 `LC_ALL`/`LANG`。详见 [docs/LOCALIZATION.md](docs/LOCALIZATION.md) 和 [docs/CONFIGURATION.md](docs/CONFIGURATION.md)。
### 切换为中文界面
+1 -1
View File
@@ -7,5 +7,5 @@ repository.workspace = true
description = "Model/provider registry and fallback strategy for DeepSeek workspace architecture"
[dependencies]
deepseek-config = { path = "../config", version = "0.8.19" }
deepseek-config = { path = "../config", version = "0.8.20" }
serde.workspace = true
+9 -9
View File
@@ -10,15 +10,15 @@ description = "Codex-style app-server transport for DeepSeek workspace architect
anyhow.workspace = true
axum.workspace = true
clap.workspace = true
deepseek-agent = { path = "../agent", version = "0.8.19" }
deepseek-config = { path = "../config", version = "0.8.19" }
deepseek-core = { path = "../core", version = "0.8.19" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.19" }
deepseek-hooks = { path = "../hooks", version = "0.8.19" }
deepseek-mcp = { path = "../mcp", version = "0.8.19" }
deepseek-protocol = { path = "../protocol", version = "0.8.19" }
deepseek-state = { path = "../state", version = "0.8.19" }
deepseek-tools = { path = "../tools", version = "0.8.19" }
deepseek-agent = { path = "../agent", version = "0.8.20" }
deepseek-config = { path = "../config", version = "0.8.20" }
deepseek-core = { path = "../core", version = "0.8.20" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.20" }
deepseek-hooks = { path = "../hooks", version = "0.8.20" }
deepseek-mcp = { path = "../mcp", version = "0.8.20" }
deepseek-protocol = { path = "../protocol", version = "0.8.20" }
deepseek-state = { path = "../state", version = "0.8.20" }
deepseek-tools = { path = "../tools", version = "0.8.20" }
serde.workspace = true
serde_json.workspace = true
tokio.workspace = true
+7 -7
View File
@@ -14,13 +14,13 @@ path = "src/main.rs"
anyhow.workspace = true
clap.workspace = true
clap_complete.workspace = true
deepseek-agent = { path = "../agent", version = "0.8.19" }
deepseek-app-server = { path = "../app-server", version = "0.8.19" }
deepseek-config = { path = "../config", version = "0.8.19" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.19" }
deepseek-mcp = { path = "../mcp", version = "0.8.19" }
deepseek-secrets = { path = "../secrets", version = "0.8.19" }
deepseek-state = { path = "../state", version = "0.8.19" }
deepseek-agent = { path = "../agent", version = "0.8.20" }
deepseek-app-server = { path = "../app-server", version = "0.8.20" }
deepseek-config = { path = "../config", version = "0.8.20" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.20" }
deepseek-mcp = { path = "../mcp", version = "0.8.20" }
deepseek-secrets = { path = "../secrets", version = "0.8.20" }
deepseek-state = { path = "../state", version = "0.8.20" }
chrono.workspace = true
dirs.workspace = true
serde.workspace = true
+1 -1
View File
@@ -8,7 +8,7 @@ description = "Config schema and precedence model for DeepSeek workspace archite
[dependencies]
anyhow.workspace = true
deepseek-secrets = { path = "../secrets", version = "0.8.19" }
deepseek-secrets = { path = "../secrets", version = "0.8.20" }
dirs.workspace = true
serde.workspace = true
toml.workspace = true
+8 -8
View File
@@ -9,13 +9,13 @@ description = "Core runtime boundaries for DeepSeek workspace architecture"
[dependencies]
anyhow.workspace = true
chrono.workspace = true
deepseek-agent = { path = "../agent", version = "0.8.19" }
deepseek-config = { path = "../config", version = "0.8.19" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.19" }
deepseek-hooks = { path = "../hooks", version = "0.8.19" }
deepseek-mcp = { path = "../mcp", version = "0.8.19" }
deepseek-protocol = { path = "../protocol", version = "0.8.19" }
deepseek-state = { path = "../state", version = "0.8.19" }
deepseek-tools = { path = "../tools", version = "0.8.19" }
deepseek-agent = { path = "../agent", version = "0.8.20" }
deepseek-config = { path = "../config", version = "0.8.20" }
deepseek-execpolicy = { path = "../execpolicy", version = "0.8.20" }
deepseek-hooks = { path = "../hooks", version = "0.8.20" }
deepseek-mcp = { path = "../mcp", version = "0.8.20" }
deepseek-protocol = { path = "../protocol", version = "0.8.20" }
deepseek-state = { path = "../state", version = "0.8.20" }
deepseek-tools = { path = "../tools", version = "0.8.20" }
serde_json.workspace = true
uuid.workspace = true
+1 -1
View File
@@ -8,5 +8,5 @@ description = "Execution policy and approval model parity for DeepSeek workspace
[dependencies]
anyhow.workspace = true
deepseek-protocol = { path = "../protocol", version = "0.8.19" }
deepseek-protocol = { path = "../protocol", version = "0.8.20" }
serde.workspace = true
+1 -1
View File
@@ -10,7 +10,7 @@ description = "Hook dispatch and notifications parity for DeepSeek workspace arc
anyhow.workspace = true
async-trait.workspace = true
chrono.workspace = true
deepseek-protocol = { path = "../protocol", version = "0.8.19" }
deepseek-protocol = { path = "../protocol", version = "0.8.20" }
reqwest.workspace = true
serde.workspace = true
serde_json.workspace = true
+1 -1
View File
@@ -9,7 +9,7 @@ description = "Tool invocation lifecycle, schema validation, and scheduler paral
[dependencies]
anyhow.workspace = true
async-trait.workspace = true
deepseek-protocol = { path = "../protocol", version = "0.8.19" }
deepseek-protocol = { path = "../protocol", version = "0.8.20" }
serde.workspace = true
serde_json.workspace = true
tokio.workspace = true
+2 -2
View File
@@ -21,8 +21,8 @@ path = "src/main.rs"
[dependencies]
anyhow = "1.0.100"
arboard = "3.4"
deepseek-secrets = { path = "../secrets", version = "0.8.19" }
deepseek-tools = { path = "../tools", version = "0.8.19" }
deepseek-secrets = { path = "../secrets", version = "0.8.20" }
deepseek-tools = { path = "../tools", version = "0.8.20" }
schemaui = { version = "0.12.0", default-features = false, optional = true }
async-stream = "0.3.6"
async-trait = "0.1"
+20 -2
View File
@@ -618,8 +618,8 @@ mod tests {
fn package_version_is_current_hotfix_release() {
assert_eq!(
env!("CARGO_PKG_VERSION"),
"0.8.19",
"0.8.19 release branch must report the release version before publishing"
"0.8.20",
"0.8.20 release branch must report the release version before publishing"
);
}
@@ -775,6 +775,24 @@ mod tests {
}
}
#[test]
fn language_mirroring_prioritizes_latest_user_message_over_locale_default() {
let prompt = compose_prompt(AppMode::Agent, Personality::Calm);
assert!(
prompt.contains("latest user message first"),
"the language directive must choose the turn language from the user message before \
falling back to the environment locale"
);
assert!(
prompt.contains("even when the `lang` field in `## Environment` is `en`"),
"Chinese user text must override an English resolved locale for reasoning_content"
);
assert!(
prompt.contains("Use the `lang` field only when"),
"environment locale should be an ambiguity fallback, not the primary language source"
);
}
/// #358: rlm guidance was reframed from "first-class" to "specialty
/// tool" — verify the structural markers are present so a future
/// change doesn't silently remove the RLM section entirely.
+1 -1
View File
@@ -2,7 +2,7 @@ You are DeepSeek TUI. You're already running inside it — don't try to launch a
## Language
Use the language indicated by the `lang` field in the `## Environment` section as your default — both for `reasoning_content` and for the final reply. For example, when `lang` resolves to a Simplified Chinese tag (`zh-Hans`, `zh-CN`, …) reason and reply in Simplified Chinese; when it is `ja` use Japanese. If the user writes in a different language during the session, switch with them. When `lang` is missing or ambiguous, fall back to detecting the user's writing.
Choose the natural language for each turn from the latest user message first — both for `reasoning_content` and for the final reply. If the latest user message is Simplified Chinese (简体中文), your `reasoning_content` and final reply must both be in Simplified Chinese, even when the `lang` field in `## Environment` is `en`. If the user switches languages mid-session, switch with them. Use the `lang` field only when the latest user message is missing, mostly code/logs, or otherwise ambiguous.
Code, file paths, identifiers, tool names, environment variables, command-line flags, URLs, and log lines stay in their original form — translating `read_file` to `读取文件` would break tool calls. Only natural-language prose mirrors the user.
+4 -2
View File
@@ -288,8 +288,10 @@ Common settings keys:
- `locale` (`auto`, `en`, `ja`, `zh-Hans`, `pt-BR`; default `auto`): UI chrome
locale. `auto` checks `LC_ALL`, `LC_MESSAGES`, then `LANG`; unsupported or
missing locales fall back to English. The runtime also exposes the resolved
locale in the system prompt so V4 models use it as the default natural
language for reasoning and replies.
locale in the system prompt as the fallback natural language for V4 reasoning
and replies when the latest user message is ambiguous. Clear user language
still takes priority; Chinese turns should produce Chinese `reasoning_content`
and Chinese final replies even when the resolved locale is English.
- `background_color` (`#RRGGBB`, `RRGGBB`, or `default`): optional main TUI
background color applied to the root, header, transcript, and footer
surfaces while preserving panel contrast.
+1 -1
View File
@@ -24,7 +24,7 @@ Use a pinned release tag for reproducible installs:
docker run --rm -it \
-e DEEPSEEK_API_KEY="$DEEPSEEK_API_KEY" \
-v ~/.deepseek:/home/deepseek/.deepseek \
ghcr.io/hmbown/deepseek-tui:v0.8.19
ghcr.io/hmbown/deepseek-tui:v0.8.20
```
## Local build
+4 -3
View File
@@ -37,9 +37,10 @@ Fallback:
- Missing or unsupported configured locales fall back to English.
- `auto` falls back to English when no supported environment locale is detected.
- The resolved locale is included in the system prompt and used as the default
natural language for V4 reasoning and replies. Users can still switch
languages mid-session by writing in a different language.
- The resolved locale is included in the system prompt as the fallback natural
language for V4 reasoning and replies. The latest user message takes priority,
including for `reasoning_content`, so a Chinese turn should remain Chinese
even when the resolved locale is English.
## Planned Global South QA Matrix
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "deepseek-tui",
"version": "0.8.19",
"deepseekBinaryVersion": "0.8.19",
"version": "0.8.20",
"deepseekBinaryVersion": "0.8.20",
"description": "Install and run deepseek and deepseek-tui binaries from GitHub release artifacts.",
"author": "Hmbown",
"license": "MIT",