ForcePilot/web/src/composables/useApproval.js

112 lines
3.1 KiB
JavaScript
Raw Normal View History

import { reactive } from 'vue'
import { normalizeQuestions } from '@/utils/questionUtils'
2026-06-06 17:46:19 +08:00
const APPROVAL_REQUIRED_STATUSES = new Set([
'ask_user_question_required',
'human_approval_required'
])
const extractQuestionPayload = (chunk) => {
const interruptInfo = chunk?.interrupt_info || {}
const rawQuestions = chunk?.questions || interruptInfo?.questions || []
const source = chunk?.source || interruptInfo?.source || 'interrupt'
const questions = normalizeQuestions(rawQuestions)
return {
questions,
source
}
}
2026-06-06 17:46:19 +08:00
export const extractPendingInterrupt = (chunk, threadId) => {
const payload = extractQuestionPayload(chunk)
if (!payload.questions.length) return null
return {
questions: payload.questions,
source: payload.source,
status: chunk?.status || '',
threadId: chunk?.thread_id || threadId,
parentRunId: chunk?.run_id || chunk?.parent_run_id || null
}
}
export function useApproval({ getThreadState, fetchThreadMessages }) {
const approvalState = reactive({
showModal: false,
questions: [],
status: '',
threadId: null,
parentRunId: null
})
2026-06-06 17:46:19 +08:00
const applyInterruptToApprovalState = (pendingInterrupt, fallbackThreadId) => {
approvalState.showModal = true
approvalState.questions = pendingInterrupt.questions
approvalState.status = pendingInterrupt.status || ''
approvalState.threadId = pendingInterrupt.threadId || fallbackThreadId
approvalState.parentRunId = pendingInterrupt.parentRunId || null
}
const clearApprovalState = () => {
approvalState.showModal = false
approvalState.questions = []
approvalState.status = ''
approvalState.threadId = null
approvalState.parentRunId = null
}
const processApprovalInStream = (chunk, threadId, currentAgentId) => {
2026-06-06 17:46:19 +08:00
if (!APPROVAL_REQUIRED_STATUSES.has(chunk.status)) {
return false
}
const threadState = getThreadState(threadId)
if (!threadState) return false
2026-06-06 17:46:19 +08:00
const pendingInterrupt = extractPendingInterrupt(chunk, threadId)
if (!pendingInterrupt) return false
threadState.isStreaming = false
2026-06-06 17:46:19 +08:00
threadState.pendingInterrupt = pendingInterrupt
2026-06-06 17:46:19 +08:00
applyInterruptToApprovalState(pendingInterrupt, threadId)
fetchThreadMessages({ agentId: currentAgentId, threadId })
return true
}
2026-06-06 17:46:19 +08:00
const restoreInterruptFromThreadState = (threadId) => {
const threadState = getThreadState(threadId)
const pendingInterrupt = threadState?.pendingInterrupt
if (!pendingInterrupt?.questions?.length) return false
threadState.isStreaming = false
threadState.replyLoadingVisible = false
threadState.pendingRequestId = null
applyInterruptToApprovalState(pendingInterrupt, threadId)
return true
}
const hideApprovalState = () => {
clearApprovalState()
}
const resetApprovalState = () => {
2026-06-06 17:46:19 +08:00
const threadState = getThreadState(approvalState.threadId)
if (threadState) {
threadState.pendingInterrupt = null
}
clearApprovalState()
}
return {
approvalState,
processApprovalInStream,
2026-06-06 17:46:19 +08:00
restoreInterruptFromThreadState,
hideApprovalState,
resetApprovalState
}
}