ForcePilot/web/src/composables/useApproval.js

157 lines
4.6 KiB
JavaScript

import { reactive } from 'vue'
import { message } from 'ant-design-vue'
import { handleChatError } from '@/utils/errorHandler'
import { agentApi } from '@/apis'
const normalizeOptions = (rawOptions) => {
if (!Array.isArray(rawOptions)) return []
return rawOptions
.map((item) => {
if (item && typeof item === 'object') {
const label = String(item.label || item.value || '').trim()
const value = String(item.value || item.label || '').trim()
return label && value ? { label, value } : null
}
const text = String(item || '').trim()
return text ? { label: text, value: text } : null
})
.filter(Boolean)
}
const extractQuestionPayload = (chunk) => {
const interruptInfo = chunk?.interrupt_info || {}
const rawOptions = chunk?.options || interruptInfo?.options || []
const options = normalizeOptions(rawOptions)
const operation = chunk?.operation || interruptInfo?.operation || ''
const source = chunk?.source || interruptInfo?.source || 'interrupt'
const multiSelect = Boolean(chunk?.multi_select ?? interruptInfo?.multi_select ?? false)
const allowOther = Boolean(chunk?.allow_other ?? interruptInfo?.allow_other ?? true)
const questionId = chunk?.question_id || interruptInfo?.question_id || ''
const question = chunk?.question || interruptInfo?.question || '请选择一个选项'
return {
questionId,
question,
options,
multiSelect,
allowOther,
source,
operation
}
}
export function useApproval({ getThreadState, resetOnGoingConv, fetchThreadMessages }) {
const approvalState = reactive({
showModal: false,
questionId: '',
question: '',
operation: '',
options: [],
multiSelect: false,
allowOther: true,
source: '',
threadId: null
})
const handleApproval = async (answer, currentAgentId, agentConfigId = null) => {
const threadId = approvalState.threadId
if (!threadId) {
message.error('无效的提问请求')
approvalState.showModal = false
return
}
const threadState = getThreadState(threadId)
if (!threadState) {
message.error('无法找到对应的对话线程')
approvalState.showModal = false
return
}
approvalState.showModal = false
if (threadState.streamAbortController) {
threadState.streamAbortController.abort()
threadState.streamAbortController = null
}
threadState.isStreaming = true
resetOnGoingConv(threadId)
threadState.streamAbortController = new AbortController()
const requestBody = {
thread_id: threadId,
answer,
config: agentConfigId ? { agent_config_id: agentConfigId } : {}
}
try {
const response = await agentApi.resumeAgentChat(currentAgentId, requestBody, {
signal: threadState.streamAbortController?.signal
})
if (!response.ok) {
const errorText = await response.text()
throw new Error(`HTTP error! status: ${response.status}, details: ${errorText}`)
}
return response
} catch (error) {
if (error.name !== 'AbortError') {
handleChatError(error, 'resume')
message.error(`恢复对话失败: ${error.message || '未知错误'}`)
}
threadState.isStreaming = false
threadState.streamAbortController = null
throw error
}
}
const processApprovalInStream = (chunk, threadId, currentAgentId) => {
if (chunk.status !== 'ask_user_question_required' && chunk.status !== 'human_approval_required') {
return false
}
const threadState = getThreadState(threadId)
if (!threadState) return false
const payload = extractQuestionPayload(chunk)
threadState.isStreaming = false
approvalState.showModal = true
approvalState.questionId = payload.questionId
approvalState.question = payload.question
approvalState.operation = payload.operation
approvalState.options = payload.options
approvalState.multiSelect = payload.multiSelect
approvalState.allowOther = payload.allowOther
approvalState.source = payload.source
approvalState.threadId = chunk.thread_id || threadId
fetchThreadMessages({ agentId: currentAgentId, threadId })
return true
}
const resetApprovalState = () => {
approvalState.showModal = false
approvalState.questionId = ''
approvalState.question = ''
approvalState.operation = ''
approvalState.options = []
approvalState.multiSelect = false
approvalState.allowOther = true
approvalState.source = ''
approvalState.threadId = null
}
return {
approvalState,
handleApproval,
processApprovalInStream,
resetApprovalState
}
}