feat(m174): 助手(AI)提供商配置真接线 + 「测试连接」
设置页新增第 6 组「助手」:提供商四态 / 端点 base_url / 模型名 / API 密钥(默认掩码, 点「显示」才明文)+ 保存 + 测试连接,四类失败(鉴权 / 模型不存在 / 不可达 / 超时)各自 一句文案 + 目标与耗时。 取舍三条: 1. 读写走 `core::setting` 的 schema API(`SettingStore::load` 现读 → `set` → `save`), 不经 `AppCommand::SetSetting`——那条指令是可序列化 DTO,`ai.api_key` 走它等于让明文进 事件流/日志。与 `SettingsBridge::persist` 写外观是同一条做法。 2. 「测试连接」不另写一套 HTTP:`unlucky_cli::commands::agent::probe` 现读设置文件、 交给 `RigProvider`(真 provider)发一次最小补全,带 8 秒时限;分类只看错误文本 (rig 只给 Display),四类各有一条真 TCP 假服务器用例钉住。 3. `ProviderKind` 补 `from_setting` / `setting_value`:serde 的 `rename_all = snake_case` 产出 `open_ai_compatible`,与 schema 的 `openai_compatible` 不是同一个词——这正是 M174 之前「agent 侧一次都没读过设置」的根因。 守卫(都做变异验证,见 mission 报告):密钥不出 `Debug`/`detail`/DTO;未配置时工厂构造 计数为 0;改完 base_url 后探测打到新地址;空/非法值被 schema 拦下且文件不动。 i18n:49 条中英各一(金表按 `Key::ALL` 位置插入);presenter 的 ai_group 补上 schema 允许 的 `disabled` 选项与一行「已配置 N 字符」的只读状态(仍然不显示值)。
This commit is contained in:
1 parent
82f3bbbff6
commit
9cb605f316
23 files changed
+2939
-73
No files matched your search
@@ -29,6 +29,59 @@ pub(super) const ROWS: &[(&str, &str, &str)] = &[
|
||||
("SettingsAppearanceCornerSquare", "Square", "直角"),
|
||||
("SettingsAppearanceCornerHint", "On Windows 11 and Server 2025 we ask the system for rounded corners; Windows 10 keeps square corners. On macOS and Linux the desktop's own rules apply. We never draw corners ourselves.", "Windows 11 与 Windows Server 2025 上我们请求系统处理外框圆角;Windows 10 保持直角;macOS 与 Linux 交给桌面合成器自己的规则;我们不自己画圆角。"),
|
||||
("SettingsAppearanceCornerSuspended", "Not in effect right now: window transparency is below 100%. Setting it back to 100% restores the rounded corners.", "当前因整窗透明度不生效:把整窗透明度调回 100% 圆角即恢复。"),
|
||||
// M174:设置页「助手(AI)」分组(`catalog/settings/ai.rs` 的 `settings_ai_entries`)。
|
||||
// 位置就是装配链里那个域的位置:`settings_ai_entries` 在 `settings_download_entries` 之后、
|
||||
// `core_text_entries` 之前,所以这几行必须落在 `SettingsAppearanceCornerSuspended` 与
|
||||
// `CoreTextUntranslated` 之间(顺序 = `Key::ALL`)。
|
||||
("SettingsGroupAssistant", "Assistant", "助手"),
|
||||
("SettingsAiStatusLabel", "Status: {status}", "状态:{status}"),
|
||||
("SettingsAiStatusUnconfigured", "not configured", "未配置"),
|
||||
("SettingsAiStatusConfigured", "configured", "已配置"),
|
||||
("SettingsAiStatusVerified", "verified", "连接已通过"),
|
||||
("SettingsAiStatusTestFailed", "test failed", "测试失败"),
|
||||
("SettingsAiEnable", "Enable the assistant", "启用助手"),
|
||||
("SettingsAiEnableHint", "With this off, the assistant stays quiet; crash diagnosis from the rule engine keeps working.", "关掉之后助手不再工作;规则引擎的崩溃诊断照常可用。"),
|
||||
("SettingsAiProviderLabel", "Provider", "提供商"),
|
||||
("SettingsAiProviderOpenAi", "OpenAI compatible", "OpenAI 兼容"),
|
||||
("SettingsAiProviderAnthropic", "Anthropic", "Anthropic 原生"),
|
||||
("SettingsAiProviderOllama", "Ollama", "Ollama 原生"),
|
||||
("SettingsAiProviderDisabled", "Disabled", "已禁用"),
|
||||
("SettingsAiBaseUrl", "Endpoint (base_url)", "端点(base_url)"),
|
||||
("SettingsAiBaseUrlPlaceholder", "http://127.0.0.1:8080/v1", "例:http://127.0.0.1:8080/v1"),
|
||||
("SettingsAiBaseUrlHint", "The /v1 root of an OpenAI-compatible service. Leave empty to use the provider default.", "OpenAI 兼容服务的 /v1 根地址;留空则用该提供商的默认端点。"),
|
||||
("SettingsAiEffective", "Effective: {value}", "生效:{value}"),
|
||||
("SettingsAiModel", "Model name", "模型名称"),
|
||||
("SettingsAiModelPlaceholder", "deepseek-chat", "例:deepseek-chat"),
|
||||
("SettingsAiApiKey", "API key", "API 密钥"),
|
||||
("SettingsAiApiKeyPlaceholder", "Paste the key", "粘贴密钥"),
|
||||
("SettingsAiApiKeyConfigured", "A key is stored ({chars} characters). Leave this empty to keep it.", "已保存密钥({chars} 个字符)。留空则保持不变。"),
|
||||
("SettingsAiApiKeyMissing", "No key stored yet", "还没有保存密钥"),
|
||||
("SettingsAiShow", "Show", "显示"),
|
||||
("SettingsAiHide", "Hide", "隐藏"),
|
||||
("SettingsAiSave", "Save", "保存"),
|
||||
("SettingsAiTest", "Test connection", "测试连接"),
|
||||
("SettingsAiTesting", "Testing…", "正在测试…"),
|
||||
("SettingsAiSaved", "Saved. It takes effect immediately, no restart needed.", "已保存,立刻生效,不用重启。"),
|
||||
("SettingsAiRefused", "Not saved: {reason}", "未保存:{reason}"),
|
||||
("SettingsAiUnsaved", "There are unsaved changes.", "有未保存的改动。"),
|
||||
("SettingsAiNoStorage", "No settings file is available in this run, so nothing can be saved or tested.", "这一次运行没有可用的设置文件,保存与测试都做不了。"),
|
||||
("SettingsAiTestDisabled", "Fill in the missing field before testing: {missing}.", "先补上这一项再测试:{missing}。"),
|
||||
("SettingsAiMissingDisabled", "the assistant is disabled", "助手处于关闭状态"),
|
||||
("SettingsAiMissingBaseUrl", "the endpoint address", "端点地址"),
|
||||
("SettingsAiMissingModel", "the model name", "模型名称"),
|
||||
("SettingsAiMissingApiKey", "the API key", "API 密钥"),
|
||||
("SettingsAiReasonProvider", "the provider value is not recognised", "提供商取值不认识"),
|
||||
("SettingsAiReasonBaseUrl", "the endpoint must start with http:// or https://", "端点必须以 http:// 或 https:// 开头"),
|
||||
("SettingsAiReasonModel", "the model name is required", "必须填模型名称"),
|
||||
("SettingsAiTestPassed", "Connected — the endpoint answered.", "连接通过 —— 端点有正常回应。"),
|
||||
("SettingsAiTestAuth", "Authentication failed: the endpoint rejected the key.", "鉴权失败:端点拒绝了这个密钥。"),
|
||||
("SettingsAiTestModel", "The endpoint answered, but this model does not exist.", "端点通了,但没有这个模型。"),
|
||||
("SettingsAiTestUnreachable", "The endpoint is unreachable.", "端点不可达。"),
|
||||
("SettingsAiTestTimeout", "Timed out while waiting for the endpoint.", "等端点回应超时了。"),
|
||||
("SettingsAiTestOther", "The request failed for another reason (see the detail below).", "请求因为别的原因失败了(详情见下)。"),
|
||||
("SettingsAiTestNotConfigured", "Nothing was sent: the configuration is incomplete.", "什么都没有发出去:配置还不完整。"),
|
||||
("SettingsAiTestTarget", "Target: {base_url} · model {model} · {ms} ms", "目标:{base_url} · 模型 {model} · {ms} 毫秒"),
|
||||
("SettingsAiTestDetail", "Detail: {detail}", "详情:{detail}"),
|
||||
("CoreTextUntranslated", "[system text not translated]", "[未翻译的系统文案]"),
|
||||
("DownloadTitle", "Version management", "版本管理"),
|
||||
("DownloadSubtitle", "Manage versions and loaders: install, upgrade, repair", "管理版本与加载器:安装、升级、修复"),
|
||||
|
||||
@@ -1,12 +1,95 @@
|
||||
//! 设置页「AI / About」分组文案:**预留**(页面上还没有这个分组,见 `pages/settings/mod.rs` 的
|
||||
//! 分组注册表)。
|
||||
//! 设置页「助手(AI)」分组文案(M174):状态矩阵四档 + 五个输入项 + 测试连接六档。
|
||||
//!
|
||||
//! 加 key 时把条目写进 `$($acc)*` 后面即可(形状见 [`crate::catalog`] 的「域装配」一节)。
|
||||
//! 现在没有条目,所以本宏是**空转移器**:只把累积表原样交给下一个域。
|
||||
//! 域文件的形状见 [`crate::catalog`] 的「域装配」一节。本域在装配链里排在
|
||||
//! `settings_download_entries` 之后、`core_text_entries` 之前(设置页五域的位置),
|
||||
//! 所以金表那几行也要插在 `SettingsAppearanceCornerSuspended` 之后——**顺序即 `Key::ALL`**。
|
||||
//!
|
||||
//! 三条口径:
|
||||
//!
|
||||
//! 1. **失败四种各写各的句子**(鉴权 / 模型不存在 / 不可达 / 超时):合成一句「测试失败」等于
|
||||
//! 让用户自己猜是 key 错了还是地址错了;
|
||||
//! 2. 密钥的**值**永远不进文案:只有 `{chars}`(已存字符数)与「未配置」两种说法;
|
||||
//! 3. 技术名词不翻:`base_url` / `OpenAI` / `Anthropic` / `Ollama` 原样。
|
||||
|
||||
macro_rules! settings_ai_entries {
|
||||
($next:ident, $($rest:ident,)* { $($acc:tt)* }) => {
|
||||
$next! { $($rest,)* { $($acc)* } }
|
||||
$next! { $($rest,)* {
|
||||
$($acc)*
|
||||
// ── 左列分组名(与 NavSettings 同源:左列是导航,标题在正文里)
|
||||
SettingsGroupAssistant => ("Assistant", "助手"),
|
||||
// ── 状态矩阵(未配置 / 已配置 / 已通过 / 测试失败)
|
||||
SettingsAiStatusLabel => ("Status: {status}", "状态:{status}"),
|
||||
SettingsAiStatusUnconfigured => ("not configured", "未配置"),
|
||||
SettingsAiStatusConfigured => ("configured", "已配置"),
|
||||
SettingsAiStatusVerified => ("verified", "连接已通过"),
|
||||
SettingsAiStatusTestFailed => ("test failed", "测试失败"),
|
||||
// ── 开关
|
||||
SettingsAiEnable => ("Enable the assistant", "启用助手"),
|
||||
SettingsAiEnableHint => (
|
||||
"With this off, the assistant stays quiet; crash diagnosis from the rule engine keeps working.",
|
||||
"关掉之后助手不再工作;规则引擎的崩溃诊断照常可用。"
|
||||
),
|
||||
// ── 提供商
|
||||
SettingsAiProviderLabel => ("Provider", "提供商"),
|
||||
SettingsAiProviderOpenAi => ("OpenAI compatible", "OpenAI 兼容"),
|
||||
SettingsAiProviderAnthropic => ("Anthropic", "Anthropic 原生"),
|
||||
SettingsAiProviderOllama => ("Ollama", "Ollama 原生"),
|
||||
SettingsAiProviderDisabled => ("Disabled", "已禁用"),
|
||||
// ── 端点 / 模型
|
||||
SettingsAiBaseUrl => ("Endpoint (base_url)", "端点(base_url)"),
|
||||
SettingsAiBaseUrlPlaceholder => ("http://127.0.0.1:8080/v1", "例:http://127.0.0.1:8080/v1"),
|
||||
SettingsAiBaseUrlHint => (
|
||||
"The /v1 root of an OpenAI-compatible service. Leave empty to use the provider default.",
|
||||
"OpenAI 兼容服务的 /v1 根地址;留空则用该提供商的默认端点。"
|
||||
),
|
||||
SettingsAiEffective => ("Effective: {value}", "生效:{value}"),
|
||||
SettingsAiModel => ("Model name", "模型名称"),
|
||||
SettingsAiModelPlaceholder => ("deepseek-chat", "例:deepseek-chat"),
|
||||
// ── 密钥(只有字符数与掩码,没有值)
|
||||
SettingsAiApiKey => ("API key", "API 密钥"),
|
||||
SettingsAiApiKeyPlaceholder => ("Paste the key", "粘贴密钥"),
|
||||
SettingsAiApiKeyConfigured => (
|
||||
"A key is stored ({chars} characters). Leave this empty to keep it.",
|
||||
"已保存密钥({chars} 个字符)。留空则保持不变。"
|
||||
),
|
||||
SettingsAiApiKeyMissing => ("No key stored yet", "还没有保存密钥"),
|
||||
SettingsAiShow => ("Show", "显示"),
|
||||
SettingsAiHide => ("Hide", "隐藏"),
|
||||
// ── 动作与回执
|
||||
SettingsAiSave => ("Save", "保存"),
|
||||
SettingsAiTest => ("Test connection", "测试连接"),
|
||||
SettingsAiTesting => ("Testing…", "正在测试…"),
|
||||
SettingsAiSaved => ("Saved. It takes effect immediately, no restart needed.", "已保存,立刻生效,不用重启。"),
|
||||
SettingsAiRefused => ("Not saved: {reason}", "未保存:{reason}"),
|
||||
SettingsAiUnsaved => ("There are unsaved changes.", "有未保存的改动。"),
|
||||
SettingsAiNoStorage => (
|
||||
"No settings file is available in this run, so nothing can be saved or tested.",
|
||||
"这一次运行没有可用的设置文件,保存与测试都做不了。"
|
||||
),
|
||||
SettingsAiTestDisabled => (
|
||||
"Fill in the missing field before testing: {missing}.",
|
||||
"先补上这一项再测试:{missing}。"
|
||||
),
|
||||
// ── 缺项(四种各说各的)
|
||||
SettingsAiMissingDisabled => ("the assistant is disabled", "助手处于关闭状态"),
|
||||
SettingsAiMissingBaseUrl => ("the endpoint address", "端点地址"),
|
||||
SettingsAiMissingModel => ("the model name", "模型名称"),
|
||||
SettingsAiMissingApiKey => ("the API key", "API 密钥"),
|
||||
// ── 拒绝保存的原因(本地校验)
|
||||
SettingsAiReasonProvider => ("the provider value is not recognised", "提供商取值不认识"),
|
||||
SettingsAiReasonBaseUrl => ("the endpoint must start with http:// or https://", "端点必须以 http:// 或 https:// 开头"),
|
||||
SettingsAiReasonModel => ("the model name is required", "必须填模型名称"),
|
||||
// ── 测试结论(六档)
|
||||
SettingsAiTestPassed => ("Connected — the endpoint answered.", "连接通过 —— 端点有正常回应。"),
|
||||
SettingsAiTestAuth => ("Authentication failed: the endpoint rejected the key.", "鉴权失败:端点拒绝了这个密钥。"),
|
||||
SettingsAiTestModel => ("The endpoint answered, but this model does not exist.", "端点通了,但没有这个模型。"),
|
||||
SettingsAiTestUnreachable => ("The endpoint is unreachable.", "端点不可达。"),
|
||||
SettingsAiTestTimeout => ("Timed out while waiting for the endpoint.", "等端点回应超时了。"),
|
||||
SettingsAiTestOther => ("The request failed for another reason (see the detail below).", "请求因为别的原因失败了(详情见下)。"),
|
||||
SettingsAiTestNotConfigured => ("Nothing was sent: the configuration is incomplete.", "什么都没有发出去:配置还不完整。"),
|
||||
SettingsAiTestTarget => ("Target: {base_url} · model {model} · {ms} ms", "目标:{base_url} · 模型 {model} · {ms} 毫秒"),
|
||||
SettingsAiTestDetail => ("Detail: {detail}", "详情:{detail}"),
|
||||
} }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user