新增: miniapp补齐4远程命令(approve/authorize_dir/continue_loop/stop_loop 对齐Phase3 §2.2)

This commit is contained in:
2026-06-22 02:53:13 +08:00
parent 5337c7d5e3
commit 8ccdce282c
2 changed files with 124 additions and 1 deletions

View File

@@ -24,6 +24,10 @@
* - stop(): 停止生成(stop Command → device invoke ai_chat_stop)
* - regenerate(): 重发最后一条 user 消息(重新 send_message)
* - switchConversation(id): 切换会话(switch Command → device 切 active)
* - approve(toolCallId, approved): 审批工具调用(approve Command → device invoke ai_approve)
* - authorizeDir(toolCallId, decision): 路径授权(authorize_dir Command → device invoke ai_authorize_dir)
* - continueLoop(convId): 继续循环(continue_loop Command → device invoke ai_continue_loop)
* - stopLoop(convId): 停止循环(stop_loop Command → device invoke ai_stop_loop)
*/
import { ref, reactive, computed } from 'vue'
@@ -428,6 +432,84 @@ function regenerate(): void {
send(lastUserText)
}
/**
* 审批工具调用(approve Command → relay → device invoke ai_approve)
*
* Phase3 §2.2 路由表:{cmd:"approve", args:{tool_call_id, approved}}
* 对应事件:AiApprovalRequired(挂起审批列表 pendingApprovals)。
*/
function approve(toolCallId: string, approved: boolean): void {
if (!toolCallId) return
const cmd: MiniCommand = {
cmd: 'approve',
args: {
tool_call_id: toolCallId,
approved,
},
}
wsClient.send(cmd)
// 乐观从挂起列表移除(对齐 AiApprovalResult 事件处理,避免 UI 卡 pending)
const idx = pendingApprovals.findIndex((p) => p.id === toolCallId)
if (idx >= 0) pendingApprovals.splice(idx, 1)
}
/**
* 路径授权(authorize_dir Command → relay → device invoke ai_authorize_dir)
*
* Phase3 §2.2 路由表:{cmd:"authorize_dir", args:{tool_call_id, decision}}
* 对应事件:AiDirAuthRequired(决策:'once'=本次 / 'always'=永久 / 'deny'=拒绝)。
*/
function authorizeDir(toolCallId: string, decision: 'once' | 'always' | 'deny'): void {
if (!toolCallId) return
const cmd: MiniCommand = {
cmd: 'authorize_dir',
args: {
tool_call_id: toolCallId,
decision,
},
}
wsClient.send(cmd)
}
/**
* 继续循环(continue_loop Command → relay → device invoke ai_continue_loop)
*
* Phase3 §2.2 路由表:{cmd:"continue_loop", args:{conversation_id}}
* 对应场景:AiMaxRoundsReached 达最大轮次暂停后,用户选「继续」再跑一轮。
*/
function continueLoop(conversationId?: string | null): void {
const convId = conversationId ?? activeConversationId.value
if (!convId) {
console.warn('[useAiChat] continue_loop 缺 conversation_id')
return
}
const cmd: MiniCommand = {
cmd: 'continue_loop',
args: { conversation_id: convId },
}
wsClient.send(cmd)
}
/**
* 停止循环(stop_loop Command → relay → device invoke ai_stop_loop)
*
* Phase3 §2.2 路由表:{cmd:"stop_loop", args:{conversation_id}}
* 对应场景:AiMaxRoundsReached 达最大轮次暂停后,用户选「停止」彻底终止。
* 与 stop 区别:stop 是中断流式生成,stop_loop 是停止多轮 agent 循环。
*/
function stopLoop(conversationId?: string | null): void {
const convId = conversationId ?? activeConversationId.value
if (!convId) {
console.warn('[useAiChat] stop_loop 缺 conversation_id')
return
}
const cmd: MiniCommand = {
cmd: 'stop_loop',
args: { conversation_id: convId },
}
wsClient.send(cmd)
}
/** 切换会话(switch Command → device 切 active_conversation_id) */
function switchConversation(convId: string): void {
activeConversationId.value = convId
@@ -484,6 +566,10 @@ export function useAiChat() {
regenerate,
switchConversation,
newConversation,
approve,
authorizeDir,
continueLoop,
stopLoop,
handleEvent,
friendlyError,
}

View File

@@ -83,7 +83,9 @@ export type ControlMessage =
* - cmd:命令名(对齐 src-tauri command 函数名)
* - args:命令参数(对齐各 command 的参数)
*
* MVP 三条(send_message / stop / switch_conversation),其余审批/重试等留后续批。
* Phase3 §2.2 路由表全覆盖(8 条):
* - send_message / stop / switch_conversation / regenerate(MVP 已发)
* - approve / authorize_dir / continue_loop / stop_loop(阶段3 补齐,见 useAiChat.ts)
*/
export interface MiniCommand {
/** Tauri command 名 */
@@ -108,3 +110,38 @@ export interface SwitchConversationArgs {
export interface StopArgs {
conversation_id?: string | null
}
/** approve 命令参数(对齐 src-tauri ai_approve,Phase3 §2.2 路由表) */
export interface ApproveArgs {
/** 待审批的工具调用 id(对应 AiApprovalRequired 事件的 id) */
tool_call_id: string
/** 是否批准(true=批准执行,false=拒绝) */
approved: boolean
}
/**
* authorize_dir 命令参数(对齐 src-tauri ai_authorize_dir,Phase3 §2.2 路由表)
*
* decision 取值:对齐 src-tauri ai_authorize_dir 的 decision 参数
* - 'once':本次授权(下次同路径仍需问)
* - 'always':永久授权(写入会话级信任目录)
* - 'deny':拒绝(本次不授权)
*/
export interface AuthorizeDirArgs {
/** 待授权的工具调用 id(对应 AiDirAuthRequired 事件的 id) */
tool_call_id: string
/** 授权决策('once' / 'always' / 'deny') */
decision: 'once' | 'always' | 'deny'
}
/** continue_loop 命令参数(对齐 src-tauri ai_continue_loop,Phase3 §2.2 路由表) */
export interface ContinueLoopArgs {
/** 需继续运行的会话 id */
conversation_id: string
}
/** stop_loop 命令参数(对齐 src-tauri ai_stop_loop,Phase3 §2.2 路由表) */
export interface StopLoopArgs {
/** 霷停止循环的会话 id */
conversation_id: string
}