Files
adnify/src/renderer/hooks/useMessageQueue.ts
T
adnaan 1f81240245 feat: refactor OpenAI authentication to use provider credential store
- Removed OpenAI OAuth handlers and replaced them with provider credential handlers.
- Introduced ProviderCredentialStore to manage API keys and OAuth credentials.
- Migrated legacy OAuth credentials to the new provider credential structure.
- Updated IPC communication to reflect changes in credential management.
- Adjusted frontend components to utilize new credential API methods.
- Added tests for provider credential store functionality and migration logic.
2026-08-28 17:55:14 +08:00

107 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 消息队列 Hook
* 监听 Agent 执行状态,在执行完成后自动消费队列中的下一条消息
*/
import { useEffect, useRef, useCallback } from 'react'
import { useMessageQueueStore } from '@/renderer/agent/store/slices/queueSlice'
import { useAgentStore } from '@/renderer/agent/store/AgentStore'
import { useAgentCommands } from './useAgent'
import { useModeStore } from '@/renderer/modes/modeStore'
/**
* 自动消费队列的 hook
* 放在 ChatPanel 中使用,监听 streaming 状态变化
*
* 修复:使用完整的 "busy" 判断(streaming | tool_running | tool_pending
* 确保从任何忙碌状态转为 idle 时都能触发队列消费
*/
export function useMessageQueueConsumer() {
const { sendMessage } = useAgentCommands()
// 使用与 selectIsStreaming 一致的逻辑:streaming 或 tool_running 都算 busy
const isBusy = useAgentStore(state => {
const threadId = state.currentThreadId
if (!threadId) return false
const thread = state.threads[threadId]
const phase = thread?.streamState?.phase
return phase === 'streaming' || phase === 'tool_running' || phase === 'tool_pending'
})
const queue = useMessageQueueStore(s => s.queue)
const dequeue = useMessageQueueStore(s => s.dequeue)
const setMode = useModeStore(s => s.setMode)
// 用 ref 追踪上一次的 busy 状态,检测从 busy → idle 的转换
const wasBusyRef = useRef(false)
const isConsumingRef = useRef(false)
useEffect(() => {
const wasBusy = wasBusyRef.current
wasBusyRef.current = isBusy
// 从 busy 变为 idle,且队列中有消息
if (wasBusy && !isBusy && queue.length > 0 && !isConsumingRef.current) {
isConsumingRef.current = true
// 短暂延迟,让 UI 有时间更新
const timer = setTimeout(async () => {
const next = dequeue()
if (next) {
// 切换到消息对应的模式
setMode(next.chatMode)
// 发送消息
try {
await sendMessage(next.content, {
mode: next.chatMode,
threadId: next.targetThreadId,
contextItems: next.contextItems,
})
} catch {
// 发送失败不阻塞,错误已由 Agent 内部处理
}
}
isConsumingRef.current = false
}, 300)
return () => {
clearTimeout(timer)
isConsumingRef.current = false
}
}
}, [isBusy, queue.length, dequeue, sendMessage, setMode])
}
/**
* 队列操作 hook
* 提供入队、立即发送等操作
*/
export function useMessageQueueActions() {
const enqueue = useMessageQueueStore(s => s.enqueue)
const promote = useMessageQueueStore(s => s.promote)
const { abort } = useAgentCommands()
/**
* 立即发送队列中的某条消息
* 策略:将其提升到队首,等当前执行完成后自动发送
*/
const sendNow = useCallback((id: string) => {
promote(id)
}, [promote])
/**
* 强制立即发送:中断当前执行 + 立即发送
*/
const forceSendNow = useCallback(async (id: string) => {
promote(id)
abort()
// abort 后 streaming 会变为 idleuseMessageQueueConsumer 会自动消费
}, [promote, abort])
return {
enqueue,
sendNow,
forceSendNow,
}
}