新增: F-01阶段6 AiChat模型下拉+override穿透

This commit is contained in:
2026-06-17 00:50:47 +08:00
parent 63bff8bf96
commit 4c84fbc1b6
7 changed files with 256 additions and 16 deletions

View File

@@ -17,6 +17,7 @@
import { listen } from '@tauri-apps/api/event'
import { invoke } from '@tauri-apps/api/core'
import { ref } from 'vue'
import { aiApi } from '@/api'
import { useAppSettingsStore } from '@/stores/appSettings'
import { state } from '@/stores/ai'
@@ -35,6 +36,22 @@ const QUEUE_LIMIT = 10
/// 排队超时阈值(ms) — 超过后弹 confirm 让用户选择"强制发送"或继续等(B-260616-02)
const QUEUE_TIMEOUT_MS = 30_000
/**
* F-01 阶段6: 用户指定模型 override(主对话专用,模块级单例)。
*
* null=自动模式(路由器选);非空字符串=用户从下拉指定的 model_id。
* 仅主对话(agentic)生效:doSend/sendMessage/regenerate/editMessage 透传给后端,
* 标题/扫描/灵感等内部调用不读此字段(后端各自独立 IPC 不带 override)。
*
* 后端兜底(agentic.rs):override 非空且在该 provider model_configs 池中才用,
* 否则落回路由结果——绝不让 override 导致无模型。
*
* 模块级(非组件级):AiChat.vue 顶部下拉读写此 ref,发送链路读此 ref 透传,
* 单实例 AiChat 不需 props/inject 串联。切换对话时后端清 session.model_override,
* 前端应同步清(modelOverride.value = null)保持 UI 与后端一致。
*/
const modelOverride = ref<string | null>(null)
// 审批计时器(startApprovalTimer/clearApprovalTimer/clearAllApprovalTimers)已下沉到 aiShared.ts
// 打破 useAiEvents ↔ useAiSend 循环依赖。本模块 re-export 供组件使用。
@@ -80,10 +97,12 @@ async function doSend(text: string, skill?: string, force = false) {
: raw
try {
// force=true 走 force_send IPC(复位残留 generating),否则走正常 send
// F-01 阶段6: 透传 modelOverride(主对话专用,后端兜底校验池内才用)
const override = modelOverride.value
if (force) {
await aiApi.forceSend(text.trim(), lang, skill)
await aiApi.forceSend(text.trim(), lang, skill, override)
} else {
await aiApi.sendMessage(text.trim(), lang, skill)
await aiApi.sendMessage(text.trim(), lang, skill, override)
}
} catch (e) {
// IPC 失败(spawn 前/provider 配置错等):回滚 streaming 防光标卡死 + 移除 user 消息与空气泡占位;
@@ -142,7 +161,7 @@ async function regenerate() {
throw new Error(t('aiChat.regenerateUnavailable'))
}
try {
await aiApi.regenerate(convId, lang)
await aiApi.regenerate(convId, lang, modelOverride.value)
} catch (e) {
// IPC 失败:回滚 streaming + 移除占位气泡(旧回复后端已弹但前端先弹了,保持弹后态)
state.streaming = false
@@ -214,7 +233,7 @@ async function editMessage(newMessage: string) {
throw new Error(t('aiChat.editNotLastUser'))
}
try {
await aiApi.editMessage(convId, newMessage.trim(), lang)
await aiApi.editMessage(convId, newMessage.trim(), lang, modelOverride.value)
} catch (e) {
// IPC 失败:回滚 streaming + 移除占位气泡(被截断的旧回复后端已标 truncated,前端已移除)
state.streaming = false
@@ -418,6 +437,8 @@ export function useAiSend() {
stopChat,
isQueueTimedOut,
tryForceSend,
// F-01 阶段6: 模型 override(主对话专用),顶部下拉读写
modelOverride,
// 审批计时器已下沉到 aiShared.ts,此处 re-export 供组件使用
startApprovalTimer,
clearApprovalTimer,