2026-01-15 06:01:34 +08:00
|
|
|
import { reactive } from 'vue'
|
|
|
|
|
import { message } from 'ant-design-vue'
|
|
|
|
|
import { handleChatError } from '@/utils/errorHandler'
|
|
|
|
|
import { agentApi } from '@/apis'
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
export function useApproval({ getThreadState, resetOnGoingConv, fetchThreadMessages }) {
|
|
|
|
|
// 审批状态
|
|
|
|
|
const approvalState = reactive({
|
|
|
|
|
showModal: false,
|
|
|
|
|
question: '',
|
|
|
|
|
operation: '',
|
|
|
|
|
threadId: null,
|
|
|
|
|
interruptInfo: null
|
2026-01-15 06:01:34 +08:00
|
|
|
})
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
// 处理审批逻辑
|
2026-01-22 05:57:13 +08:00
|
|
|
const handleApproval = async (approved, currentAgentId, agentConfigId = null) => {
|
2026-01-15 06:01:34 +08:00
|
|
|
const threadId = approvalState.threadId
|
2025-11-01 21:34:16 +08:00
|
|
|
if (!threadId) {
|
2026-01-15 06:01:34 +08:00
|
|
|
message.error('无效的审批请求')
|
|
|
|
|
approvalState.showModal = false
|
|
|
|
|
return
|
2025-11-01 21:34:16 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
const threadState = getThreadState(threadId)
|
2025-11-01 21:34:16 +08:00
|
|
|
if (!threadState) {
|
2026-01-15 06:01:34 +08:00
|
|
|
message.error('无法找到对应的对话线程')
|
|
|
|
|
approvalState.showModal = false
|
|
|
|
|
return
|
2025-11-01 21:34:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 关闭弹窗
|
2026-01-15 06:01:34 +08:00
|
|
|
approvalState.showModal = false
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
// 清理旧的流式控制器(如果存在)
|
|
|
|
|
if (threadState.streamAbortController) {
|
2026-01-15 06:01:34 +08:00
|
|
|
threadState.streamAbortController.abort()
|
|
|
|
|
threadState.streamAbortController = null
|
2025-11-01 21:34:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 标记为处理中
|
2026-01-15 06:01:34 +08:00
|
|
|
threadState.isStreaming = true
|
|
|
|
|
resetOnGoingConv(threadId)
|
|
|
|
|
threadState.streamAbortController = new AbortController()
|
2025-11-01 21:34:16 +08:00
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
console.log('🔄 [APPROVAL] Starting resume process:', { approved, threadId, currentAgentId })
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 调用恢复接口
|
|
|
|
|
const response = await agentApi.resumeAgentChat(
|
|
|
|
|
currentAgentId,
|
|
|
|
|
{
|
|
|
|
|
thread_id: threadId,
|
2026-01-22 05:57:13 +08:00
|
|
|
approved: approved,
|
|
|
|
|
config: agentConfigId ? { agent_config_id: agentConfigId } : {}
|
2025-11-01 21:34:16 +08:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
signal: threadState.streamAbortController?.signal
|
|
|
|
|
}
|
2026-01-15 06:01:34 +08:00
|
|
|
)
|
2025-11-01 21:34:16 +08:00
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
console.log('🔄 [APPROVAL] Resume API response received')
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
if (!response.ok) {
|
2026-01-15 06:01:34 +08:00
|
|
|
const errorText = await response.text()
|
|
|
|
|
console.error('Resume API error:', response.status, errorText)
|
|
|
|
|
throw new Error(`HTTP error! status: ${response.status}, details: ${errorText}`)
|
2025-11-01 21:34:16 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
console.log('🔄 [APPROVAL] Resume API successful, returning response for stream processing')
|
|
|
|
|
return response // 返回响应供调用方处理流式数据
|
2025-11-01 21:34:16 +08:00
|
|
|
} catch (error) {
|
2026-01-15 06:01:34 +08:00
|
|
|
console.error('❌ [APPROVAL] Resume failed:', error)
|
2025-11-01 21:34:16 +08:00
|
|
|
if (error.name !== 'AbortError') {
|
2026-01-15 06:01:34 +08:00
|
|
|
handleChatError(error, 'resume')
|
|
|
|
|
message.error(`恢复对话失败: ${error.message || '未知错误'}`)
|
2025-11-01 21:34:16 +08:00
|
|
|
}
|
|
|
|
|
// 重置状态 - 只在错误时重置
|
2026-01-15 06:01:34 +08:00
|
|
|
threadState.isStreaming = false
|
|
|
|
|
threadState.streamAbortController = null
|
|
|
|
|
throw error // 重新抛出错误让调用方处理
|
2025-11-01 21:34:16 +08:00
|
|
|
}
|
|
|
|
|
// 移除 finally 块 - 让组件管理流式状态的生命周期
|
2026-01-15 06:01:34 +08:00
|
|
|
}
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
// 在流式处理中处理审批请求
|
|
|
|
|
const processApprovalInStream = (chunk, threadId, currentAgentId) => {
|
|
|
|
|
if (chunk.status !== 'human_approval_required') {
|
2026-01-15 06:01:34 +08:00
|
|
|
return false
|
2025-11-01 21:34:16 +08:00
|
|
|
}
|
|
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
const { interrupt_info } = chunk
|
|
|
|
|
const threadState = getThreadState(threadId)
|
2025-11-01 21:34:16 +08:00
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
if (!threadState) return false
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
// 停止显示"处理中"状态,让用户可以看到并操作审批弹窗
|
2026-01-15 06:01:34 +08:00
|
|
|
threadState.isStreaming = false
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
// 显示审批弹窗
|
2026-01-15 06:01:34 +08:00
|
|
|
approvalState.showModal = true
|
|
|
|
|
approvalState.question = interrupt_info?.question || '是否批准以下操作?'
|
|
|
|
|
approvalState.operation = interrupt_info?.operation || '未知操作'
|
|
|
|
|
approvalState.threadId = chunk.thread_id || threadId
|
|
|
|
|
approvalState.interruptInfo = interrupt_info
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
// 刷新消息历史显示已执行的部分
|
2026-01-15 06:01:34 +08:00
|
|
|
fetchThreadMessages({ agentId: currentAgentId, threadId: threadId })
|
2025-11-01 21:34:16 +08:00
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
return true // 表示已处理审批请求,应停止流式处理
|
|
|
|
|
}
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
// 重置审批状态
|
|
|
|
|
const resetApprovalState = () => {
|
2026-01-15 06:01:34 +08:00
|
|
|
approvalState.showModal = false
|
|
|
|
|
approvalState.question = ''
|
|
|
|
|
approvalState.operation = ''
|
|
|
|
|
approvalState.threadId = null
|
|
|
|
|
approvalState.interruptInfo = null
|
|
|
|
|
}
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
approvalState,
|
|
|
|
|
handleApproval,
|
|
|
|
|
processApprovalInStream,
|
|
|
|
|
resetApprovalState
|
2026-01-15 06:01:34 +08:00
|
|
|
}
|
|
|
|
|
}
|