2026-03-20 17:51:12 +08:00
|
|
|
const createOnGoingConvState = () => ({
|
|
|
|
|
msgChunks: {},
|
|
|
|
|
currentRequestKey: null,
|
|
|
|
|
currentAssistantKey: null,
|
|
|
|
|
toolCallBuffers: {}
|
|
|
|
|
})
|
|
|
|
|
|
2026-03-25 13:46:52 +08:00
|
|
|
export function useAgentThreadState({
|
|
|
|
|
chatState,
|
|
|
|
|
getCurrentThreadId,
|
|
|
|
|
onStopThread = null,
|
|
|
|
|
onBeforeResetThread = null,
|
|
|
|
|
onBeforeCleanupThread = null
|
|
|
|
|
}) {
|
2026-03-20 17:51:12 +08:00
|
|
|
const getThreadState = (threadId) => {
|
|
|
|
|
if (!threadId) return null
|
|
|
|
|
if (!chatState.threadStates[threadId]) {
|
|
|
|
|
chatState.threadStates[threadId] = {
|
|
|
|
|
isStreaming: false,
|
|
|
|
|
streamAbortController: null,
|
|
|
|
|
runStreamAbortController: null,
|
|
|
|
|
activeRunId: null,
|
|
|
|
|
runLastSeq: '0',
|
|
|
|
|
lastRetryableJobTry: null,
|
|
|
|
|
onGoingConv: createOnGoingConvState(),
|
|
|
|
|
agentState: null
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return chatState.threadStates[threadId]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const stopThreadStream = (threadId) => {
|
|
|
|
|
if (!threadId) return
|
|
|
|
|
const threadState = chatState.threadStates[threadId]
|
2026-03-25 13:46:52 +08:00
|
|
|
if (typeof onStopThread === 'function') {
|
|
|
|
|
onStopThread(threadId)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 17:51:12 +08:00
|
|
|
if (!threadState?.streamAbortController) return
|
|
|
|
|
|
|
|
|
|
threadState.streamAbortController.abort()
|
|
|
|
|
threadState.streamAbortController = null
|
|
|
|
|
threadState.isStreaming = false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cleanupThreadState = (threadId) => {
|
|
|
|
|
if (!threadId) return
|
|
|
|
|
const threadState = chatState.threadStates[threadId]
|
|
|
|
|
if (!threadState) return
|
|
|
|
|
|
2026-03-25 13:46:52 +08:00
|
|
|
if (typeof onBeforeCleanupThread === 'function') {
|
|
|
|
|
onBeforeCleanupThread(threadId)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 17:51:12 +08:00
|
|
|
if (threadState.streamAbortController) {
|
|
|
|
|
threadState.streamAbortController.abort()
|
|
|
|
|
}
|
|
|
|
|
if (threadState.runStreamAbortController) {
|
|
|
|
|
threadState.runStreamAbortController.abort()
|
|
|
|
|
}
|
|
|
|
|
delete chatState.threadStates[threadId]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const resetOnGoingConv = (threadId = null) => {
|
|
|
|
|
const targetThreadId =
|
|
|
|
|
threadId || (typeof getCurrentThreadId === 'function' ? getCurrentThreadId() : null)
|
|
|
|
|
|
|
|
|
|
if (targetThreadId) {
|
|
|
|
|
const threadState = getThreadState(targetThreadId)
|
|
|
|
|
if (!threadState) return
|
|
|
|
|
|
2026-03-25 13:46:52 +08:00
|
|
|
if (typeof onBeforeResetThread === 'function') {
|
|
|
|
|
onBeforeResetThread(targetThreadId)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-20 17:51:12 +08:00
|
|
|
if (threadState.streamAbortController) {
|
|
|
|
|
threadState.streamAbortController.abort()
|
|
|
|
|
threadState.streamAbortController = null
|
|
|
|
|
}
|
|
|
|
|
if (threadState.runStreamAbortController) {
|
|
|
|
|
threadState.runStreamAbortController.abort()
|
|
|
|
|
threadState.runStreamAbortController = null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
threadState.onGoingConv = createOnGoingConvState()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Object.keys(chatState.threadStates).forEach((id) => {
|
|
|
|
|
cleanupThreadState(id)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
getThreadState,
|
|
|
|
|
cleanupThreadState,
|
|
|
|
|
resetOnGoingConv,
|
|
|
|
|
stopThreadStream
|
|
|
|
|
}
|
|
|
|
|
}
|