重构: commands拆分config+skills域·commands.rs 92KB拆分完整(strategy)

- 新建 commands/config.rs(89行, 4 IPC: ai_list_skills/ai_set_concurrency_config/ai_set_agent_max_iterations/ai_set_agent_max_retries)
- commands/mod.rs 99→34行(收敛re-export only, 无IPC函数体)
- re-export三级透传(chat/conversation/provider/config),lib.rs invoke_handler+前端零改动
commands.rs 92KB拆分完整: 原1829行God→5文件(chat 1147+conversation 336+provider 348+config 89+mod.rs 34 re-export)
主代兜底: cargo check --workspace 0 + test 98 + cat mod.rs re-export only印证
strategy全程: 分批1-2文件原子操作(chat→conv→provider→config四批); 零调用方预留保留
This commit is contained in:
2026-06-19 03:26:44 +08:00
parent 6769100b57
commit f1aa7ac33d
2 changed files with 103 additions and 78 deletions

View File

@@ -0,0 +1,89 @@
//! skills + config 域 IPC — 4 个 `#[tauri::command]` 函数
//!
//! 原 `commands/ai/commands/mod.rs` 收敛到 re-export only 后,本文件承接最后一批 IPC:
//! - `ai_list_skills` — 列出本机 Claude 技能(skills + commands + plugins),供前端 `/` 联想
//! - `ai_set_concurrency_config` — LLM 并发上限运行时调整(global/per-conv,立即生效)
//! - `ai_set_agent_max_iterations` — Agentic 循环最大轮次(下次发消息生效)
//! - `ai_set_agent_max_retries` — 流式对话失败自动重试次数(下次发消息生效)
//!
//! re-export 链:本文件经 `commands/ai/commands/mod.rs` 的 `pub use self::config::*`
//! → `commands::*` → `ai/mod.rs` 的 `pub use self::commands::*` 透传到 `commands::ai::*`
//! → `lib.rs` invoke_handler + 前端 `api/ai.ts` 零改动。
//!
//! 注:`ai_list_skills` 复用 `super::super::skills::{skills_cached, SkillInfo}`(skills.rs
//! 模块提供进程内缓存 + 扫盘逻辑,本文件仅做 IPC 包装,不重复实现)。
use std::sync::atomic::Ordering;
use tauri::State;
// skills_cached(进程内缓存命中即 clone,不重复扫盘)/SkillInfo(技能统一返回结构)
// 来自 commands/ai/skills.rs,本域 IPC 复用,不重复定义。
use super::super::skills::{skills_cached, SkillInfo};
use crate::state::AppState;
/// 列出本机 Claude 技能skills + commands + plugins 三类),供前端 `/` 联想
#[tauri::command]
pub async fn ai_list_skills() -> Result<Vec<SkillInfo>, String> {
// 命中进程内缓存,命中后仅 clone不重复扫盘
Ok(skills_cached().clone())
}
/// 设置 LLM 调用并发上限(运行时调整,立即生效)
///
/// 软收敛:缩并发时已持有旧 permit 的任务继续执行不受影响,待其释放后新限制完全生效。
/// None 表示该层不变(前端可单独调一层)。值下限为 1。
#[tauri::command]
pub async fn ai_set_concurrency_config(
state: State<'_, AppState>,
global_limit: Option<u32>,
per_conv_limit: Option<u32>,
) -> Result<(), String> {
// 下限 1,无上限;同时给 global 时约束 per-conv 不超过 global
if let Some(g) = global_limit {
state.llm_concurrency.set_global(g.max(1) as usize).await;
}
if let Some(p) = per_conv_limit {
let mut p = p.max(1);
if let Some(g) = global_limit {
p = p.min(g.max(1));
}
state.llm_concurrency.set_per_conv(p as usize).await;
}
Ok(())
}
/// 设置 Agentic 循环最大轮次(运行时调整,立即生效)
///
/// 与并发配置不同max_iterations 是 loop 入口 load 快照的值,热改后当前 loop 不受影响
/// (已锁定边界),下次发消息生效。范围双 clampcommand 端 1-50 + 前端 input min/max
/// 防越界输入致 loop 过早结束(值过小)或失控(值过大)。
#[tauri::command]
pub async fn ai_set_agent_max_iterations(
state: State<'_, AppState>,
value: u32,
) -> Result<(), String> {
// clamp 1-50下限防 agent 失能(一轮即截断无法调任何工具),
// 上限防失控烧 token50 轮足够覆盖复杂多步任务)
let clamped = value.clamp(1, 50) as usize;
state.agent_max_iterations.store(clamped, Ordering::SeqCst);
Ok(())
}
/// 设置流式对话失败自动重试次数F-260616-07 / 决策 a1运行时调整下次发消息生效
///
/// 只重试流前失败Init Err未输出任何 token流中途失败MidStream Partial保文不重试。
/// 退避复用 retry::backoff_delay(1s→2s→4s+jitter) + is_status_retryable Fatal 分类 +
/// 30s 总预算(详见 agentic.rs 流前重试循环)。
/// 范围 clamp 0-100 表示不重试(直接报错),上限 10 防过度重试烧 token/拖慢体验。
/// 默认 3复用 retry.rs backoff_delay + 错误分类,详见 agentic.rs 重试循环)。
#[tauri::command]
pub async fn ai_set_agent_max_retries(
state: State<'_, AppState>,
value: u32,
) -> Result<(), String> {
let clamped = value.clamp(0, 10) as usize;
state.agent_max_retries.store(clamped, Ordering::SeqCst);
Ok(())
}

View File

@@ -1,16 +1,23 @@
//! 所有 `#[tauri::command]` IPC 函数 — 由 ai/mod.rs 重导出供 invoke_handler 引用
//!
//! 原单文件 commands.rs(1829 行 God 文件)按域拆分为 `commands/` 子目录:
//! 原单文件 commands.rs(1829 行 God 文件)按域拆分为 `commands/` 子目录,本文件收敛到 re-export only:
//! - [`chat`] — chat 域 13 个 IPC(发送/重新生成/编辑/强制发送/停止/审批/上下文分段与压缩/循环控制)
//! + chat 专用 helper(`finalize_pending_placeholders`)+ `PendingToolCallInfo`
//! - [`conversation`] — conversation 域 8 个 IPC(创建/列出/切换/删除/重命名/归档/置顶/导出)
//! - [`provider`] — provider 域 7 个 IPC(提供商 CRUD/池配置/模型拉取探测)+ provider 专用 helper
//! (`mask_api_key` api_key 脱敏、`normalize_provider_type_for_fetch` 类型归一)
//! - 本文件(`mod.rs`)保留其余域 IPC:skills/config(后续批按域继续拆分)。
//! - [`config`] — skills + config 域 4 个 IPC(ai_list_skills + ai_set_concurrency_config
//! + ai_set_agent_max_iterations + ai_set_agent_max_retries);`ai_list_skills` 复用
//! `super::super::skills::{skills_cached, SkillInfo}`(skills.rs 缓存+扫盘,config 仅 IPC 包装)
//!
//! re-export 链:`commands/mod.rs` → `pub use self::{chat,conversation,provider}::*` 把各域 IPC
//! 拉到 `commands::*` → `ai/mod.rs` 的 `pub use self::commands::*` 透传到 `commands::ai::*`
//! re-export 链:`commands/mod.rs` → `pub use self::{chat,conversation,provider,config}::*`
//! 把各域 IPC 拉到 `commands::*` → `ai/mod.rs` 的 `pub use self::commands::*` 透传到 `commands::ai::*`
//! → `lib.rs` invoke_handler + 前端 `api/ai.ts` 零改动。
//!
//! 注:本文件仅 mod + pub use 声明(re-export only),不含任何 IPC 函数体。
//! config/skills 域外的 helper(mask_api_key/finalize_pending_placeholders 等)随各域就近安置,
//! skills 域共享的 skills_cached/SkillInfo 仍由 commands/ai/skills.rs 提供,config.rs 通过
//! `super::super::skills` 路径引用,保持单一来源(DRY)。
// 各域子模块 + glob 重导出(拉到 commands::* 经 ai/mod.rs 透传到 commands::ai::*)
pub mod chat;
@@ -22,77 +29,6 @@ pub use self::conversation::*;
pub mod provider;
#[allow(unused_imports)]
pub use self::provider::*;
use std::sync::atomic::Ordering;
use tauri::State;
// skills 域(ai_list_skills)仍用 skills_cached/SkillInfo,保留。
use super::skills::{skills_cached, SkillInfo};
use crate::state::AppState;
/// 列出本机 Claude 技能skills + commands + plugins 三类),供前端 `/` 联想
#[tauri::command]
pub async fn ai_list_skills() -> Result<Vec<SkillInfo>, String> {
// 命中进程内缓存,命中后仅 clone不重复扫盘
Ok(skills_cached().clone())
}
/// 设置 LLM 调用并发上限(运行时调整,立即生效)
///
/// 软收敛:缩并发时已持有旧 permit 的任务继续执行不受影响,待其释放后新限制完全生效。
/// None 表示该层不变(前端可单独调一层)。值下限为 1。
#[tauri::command]
pub async fn ai_set_concurrency_config(
state: State<'_, AppState>,
global_limit: Option<u32>,
per_conv_limit: Option<u32>,
) -> Result<(), String> {
// 下限 1,无上限;同时给 global 时约束 per-conv 不超过 global
if let Some(g) = global_limit {
state.llm_concurrency.set_global(g.max(1) as usize).await;
}
if let Some(p) = per_conv_limit {
let mut p = p.max(1);
if let Some(g) = global_limit {
p = p.min(g.max(1));
}
state.llm_concurrency.set_per_conv(p as usize).await;
}
Ok(())
}
/// 设置 Agentic 循环最大轮次(运行时调整,立即生效)
///
/// 与并发配置不同max_iterations 是 loop 入口 load 快照的值,热改后当前 loop 不受影响
/// (已锁定边界),下次发消息生效。范围双 clampcommand 端 1-50 + 前端 input min/max
/// 防越界输入致 loop 过早结束(值过小)或失控(值过大)。
#[tauri::command]
pub async fn ai_set_agent_max_iterations(
state: State<'_, AppState>,
value: u32,
) -> Result<(), String> {
// clamp 1-50下限防 agent 失能(一轮即截断无法调任何工具),
// 上限防失控烧 token50 轮足够覆盖复杂多步任务)
let clamped = value.clamp(1, 50) as usize;
state.agent_max_iterations.store(clamped, Ordering::SeqCst);
Ok(())
}
/// 设置流式对话失败自动重试次数F-260616-07 / 决策 a1运行时调整下次发消息生效
///
/// 只重试流前失败Init Err未输出任何 token流中途失败MidStream Partial保文不重试。
/// 退避复用 retry::backoff_delay(1s→2s→4s+jitter) + is_status_retryable Fatal 分类 +
/// 30s 总预算(详见 agentic.rs 流前重试循环)。
/// 范围 clamp 0-100 表示不重试(直接报错),上限 10 防过度重试烧 token/拖慢体验。
/// 默认 3复用 retry.rs backoff_delay + 错误分类,详见 agentic.rs 重试循环)。
#[tauri::command]
pub async fn ai_set_agent_max_retries(
state: State<'_, AppState>,
value: u32,
) -> Result<(), String> {
let clamped = value.clamp(0, 10) as usize;
state.agent_max_retries.store(clamped, Ordering::SeqCst);
Ok(())
}
pub mod config;
#[allow(unused_imports)]
pub use self::config::*;