2026-01-15 06:01:34 +08:00
|
|
|
import { reactive } from 'vue'
|
2026-05-19 18:37:29 +08:00
|
|
|
import { normalizeQuestions } from '@/utils/questionUtils'
|
2026-03-07 23:28:25 +08:00
|
|
|
|
2026-06-06 17:46:19 +08:00
|
|
|
const APPROVAL_REQUIRED_STATUSES = new Set([
|
|
|
|
|
'ask_user_question_required',
|
|
|
|
|
'human_approval_required'
|
|
|
|
|
])
|
|
|
|
|
|
2026-03-07 23:28:25 +08:00
|
|
|
const extractQuestionPayload = (chunk) => {
|
|
|
|
|
const interruptInfo = chunk?.interrupt_info || {}
|
2026-03-17 03:39:48 +08:00
|
|
|
const rawQuestions = chunk?.questions || interruptInfo?.questions || []
|
2026-03-10 00:16:41 +08:00
|
|
|
const source = chunk?.source || interruptInfo?.source || 'interrupt'
|
2026-05-19 18:37:29 +08:00
|
|
|
const questions = normalizeQuestions(rawQuestions)
|
2026-03-07 23:28:25 +08:00
|
|
|
|
|
|
|
|
return {
|
2026-03-17 03:39:48 +08:00
|
|
|
questions,
|
|
|
|
|
source
|
2026-03-07 23:28:25 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-28 12:53:29 +08:00
|
|
|
export function useApproval({ getThreadState, fetchThreadMessages }) {
|
2025-11-01 21:34:16 +08:00
|
|
|
const approvalState = reactive({
|
|
|
|
|
showModal: false,
|
2026-03-17 03:39:48 +08:00
|
|
|
questions: [],
|
|
|
|
|
status: '',
|
2026-05-28 12:53:29 +08:00
|
|
|
threadId: null,
|
|
|
|
|
parentRunId: null
|
2026-01-15 06:01:34 +08:00
|
|
|
})
|
2025-11-01 21:34:16 +08:00
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-01 21:34:16 +08:00
|
|
|
const processApprovalInStream = (chunk, threadId, currentAgentId) => {
|
2026-06-06 17:46:19 +08:00
|
|
|
if (!APPROVAL_REQUIRED_STATUSES.has(chunk.status)) {
|
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 threadState = getThreadState(threadId)
|
|
|
|
|
if (!threadState) return false
|
2025-11-01 21:34:16 +08:00
|
|
|
|
2026-06-06 17:46:19 +08:00
|
|
|
const pendingInterrupt = extractPendingInterrupt(chunk, threadId)
|
|
|
|
|
if (!pendingInterrupt) return false
|
2026-03-07 23:28:25 +08:00
|
|
|
|
2026-01-15 06:01:34 +08:00
|
|
|
threadState.isStreaming = false
|
2026-06-06 17:46:19 +08:00
|
|
|
threadState.pendingInterrupt = pendingInterrupt
|
2025-11-01 21:34:16 +08:00
|
|
|
|
2026-06-06 17:46:19 +08:00
|
|
|
applyInterruptToApprovalState(pendingInterrupt, threadId)
|
2025-11-01 21:34:16 +08:00
|
|
|
|
2026-03-07 23:28:25 +08:00
|
|
|
fetchThreadMessages({ agentId: currentAgentId, threadId })
|
2025-11-01 21:34:16 +08:00
|
|
|
|
2026-03-07 23:28:25 +08:00
|
|
|
return true
|
2026-01-15 06:01:34 +08:00
|
|
|
}
|
2025-11-01 21:34:16 +08:00
|
|
|
|
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()
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-01 21:34:16 +08:00
|
|
|
const resetApprovalState = () => {
|
2026-06-06 17:46:19 +08:00
|
|
|
const threadState = getThreadState(approvalState.threadId)
|
|
|
|
|
if (threadState) {
|
|
|
|
|
threadState.pendingInterrupt = null
|
|
|
|
|
}
|
|
|
|
|
clearApprovalState()
|
2026-01-15 06:01:34 +08:00
|
|
|
}
|
2025-11-01 21:34:16 +08:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
approvalState,
|
|
|
|
|
processApprovalInStream,
|
2026-06-06 17:46:19 +08:00
|
|
|
restoreInterruptFromThreadState,
|
|
|
|
|
hideApprovalState,
|
2025-11-01 21:34:16 +08:00
|
|
|
resetApprovalState
|
2026-01-15 06:01:34 +08:00
|
|
|
}
|
|
|
|
|
}
|