新增: UX队列三件套(打断保留续发+队列编辑+立即发送)

This commit is contained in:
2026-06-16 23:59:10 +08:00
parent 8dad15ecc1
commit 313459b8e4
4 changed files with 117 additions and 4 deletions

View File

@@ -359,13 +359,47 @@ function clearQueue() {
state.queue = []
}
/**
* UX-260616-06: 编辑队列项的 text(决策只编 text)。
*
* 设计:
* - 只改 text,skill 编辑态不暴露(skill 来自发送时技能联想,编辑态改 skill 复杂化交互无收益)。
* - 边界:index 越界 / newText 空白 → 直接忽略(no-op),不抛错(UI 不会触发,防御)。
* - queue item 类型 { text, skill?, enqueuedAt } 不改。
*/
function editQueued(index: number, newText: string) {
if (index < 0 || index >= state.queue.length) return
const trimmed = newText.trim()
if (!trimmed) return
state.queue[index].text = trimmed
}
/**
* UX-260616-07: 队列项立即发送(决策 a:插队=打断当前+发本条,复用 UX-05 stop 链路)。
*
* 流程(顺序关键):
* 1. 先 splice 出该项(记下 {text, skill})——必须在 stopChat 之前,
* 否则 stopChat→AiCompleted→drainQueue 续发时该项还在队列致重复发。
* 2. 调 stopChat() 打断当前生成(stopChat UX-05 后已不清队列,故 splice 步骤前置必要)。
* 3. 直接 sendMessage(splicedItem.text, skill) 立即发这条(不等 drainQueue 轮到)。
* 当前未完成回复已由 stop 截断保留(agentic.rs:185 save_conversation),无需额外处理。
*/
async function sendQueuedNow(index: number) {
if (index < 0 || index >= state.queue.length) return
const spliced = state.queue.splice(index, 1)[0]
await stopChat()
await sendMessage(spliced.text, spliced.skill)
}
/** 停止当前生成:本地先复位 streaming再发停止信号。
* 不依赖后端 AiCompleted 收尾——审批态看门狗已 clear(useAiEvents),若 AiCompleted 竞态丢失则 streaming 永久 true 卡死,故本地兜底。
*/
async function stopChat() {
state.streaming = false // 本地先复位,不依赖后端 AiCompleted审批态看门狗已 clear竞态丢失则卡死
clearStreamWatchdog() // 清残留看门狗
state.queue = [] // B-32:用户主动停止,清队列防生成中入队的消息被静默丢弃
// UX-260616-05 决策 a(逐条续发):不再清队列,保留供 AiCompleted 链式触发 drainQueue 续发。
// 后端 agentic.rs:190 emit AiCompleted 注释明确「保证前端收事件时后端已可接下一条,队列续发不被拒」;
// 当前未完成回复已入库(agentic.rs:185 save_conversation)保留为截断回复。
await aiApi.stopChat()
}
@@ -379,6 +413,8 @@ export function useAiSend() {
drainQueue,
cancelQueued,
clearQueue,
editQueued, // UX-260616-06
sendQueuedNow, // UX-260616-07
stopChat,
isQueueTimedOut,
tryForceSend,