fix: harden long conversation continuity
Memind CI / Test, build, and release guards (push) Successful in 1m28s
Memind CI / Test, build, and release guards (push) Successful in 1m28s
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
||||
} from '../utils/imageUpload';
|
||||
import { buildAbsoluteAssetDownloadUrl } from '../utils/mindspaceCards';
|
||||
import { resolveAgentRunOptions } from '../utils/agentRunMode';
|
||||
import { shouldIgnoreZeroActivityFinish } from '../../chat-agent-run-gate.mjs';
|
||||
import {
|
||||
buildUserMessage,
|
||||
normalizeConversationMessages,
|
||||
@@ -183,6 +184,13 @@ export function usePageEditSubChat({
|
||||
activeRequestId.current = null;
|
||||
return;
|
||||
case 'Finish':
|
||||
if (shouldIgnoreZeroActivityFinish({
|
||||
eventType: event.type,
|
||||
tokenState: event.token_state,
|
||||
hasActiveRequest: Boolean(activeRequestId.current),
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
setChatState('idle');
|
||||
setPendingTool(null);
|
||||
activeRequestId.current = null;
|
||||
|
||||
@@ -58,8 +58,10 @@ import {
|
||||
import {
|
||||
reconcileSessionEventRequestContext,
|
||||
resolvePostAgentRunChatState,
|
||||
shouldIgnoreZeroActivityFinish,
|
||||
shouldKeepStreamingAfterRunError,
|
||||
shouldPromoteSessionIdToStreaming,
|
||||
shouldScheduleMissingActiveRequestGrace,
|
||||
} from '../../chat-agent-run-gate.mjs';
|
||||
import { mergeConversationSnapshot } from '../../chat-finish-sync.mjs';
|
||||
import {
|
||||
@@ -372,6 +374,7 @@ export function useTKMindChat(
|
||||
const seenNotificationIdsRef = useRef<Set<string>>(new Set());
|
||||
|
||||
const activeRequestId = useRef<string | null>(null);
|
||||
const agentRunPendingRef = useRef(false);
|
||||
const activeRequestMissingTimerRef = useRef<ReturnType<typeof window.setTimeout> | null>(null);
|
||||
const chatStateRef = useRef<ChatState>(chatState);
|
||||
const subscribedSessionIdRef = useRef<string | null>(null);
|
||||
@@ -930,14 +933,18 @@ export function useTKMindChat(
|
||||
activeRequestId.current = retryRequestId;
|
||||
setChatState('waiting');
|
||||
setError(null);
|
||||
clearActiveRequestMissingTimer();
|
||||
agentRunPendingRef.current = true;
|
||||
const retryRun = await createAgentRun(sessionRef.current!.id, retryRequestId, lastUser);
|
||||
const finishedRetryRun =
|
||||
retryRun.status === 'succeeded' ? retryRun : await waitForAgentRun(retryRun.id);
|
||||
agentRunPendingRef.current = false;
|
||||
if (!finishedRetryRun.sessionId) {
|
||||
throw new Error('后台任务已提交,但未返回会话');
|
||||
}
|
||||
setChatState('streaming');
|
||||
} catch (err) {
|
||||
agentRunPendingRef.current = false;
|
||||
setError(err instanceof Error ? err.message : String(err));
|
||||
setChatState('error');
|
||||
activeRequestId.current = null;
|
||||
@@ -950,6 +957,7 @@ export function useTKMindChat(
|
||||
: '云端 Relay 不可用,且本地 fallback 重试失败或未启用',
|
||||
);
|
||||
setChatState('error');
|
||||
agentRunPendingRef.current = false;
|
||||
activeRequestId.current = null;
|
||||
}
|
||||
return;
|
||||
@@ -986,11 +994,20 @@ export function useTKMindChat(
|
||||
case 'Error':
|
||||
setError(event.error);
|
||||
setChatState('error');
|
||||
agentRunPendingRef.current = false;
|
||||
activeRequestId.current = null;
|
||||
return;
|
||||
case 'Finish':
|
||||
if (shouldIgnoreZeroActivityFinish({
|
||||
eventType: event.type,
|
||||
tokenState: event.token_state,
|
||||
hasActiveRequest: Boolean(activeRequestId.current),
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
setChatState('idle');
|
||||
setPendingTool(null);
|
||||
agentRunPendingRef.current = false;
|
||||
activeRequestId.current = null;
|
||||
if (isDirectChatSessionId(sessionId)) {
|
||||
unsubscribeRef.current?.();
|
||||
@@ -1054,7 +1071,12 @@ export function useTKMindChat(
|
||||
rid = activeRequestContext.activeRequestId;
|
||||
} else if (rid && event.request_ids.includes(rid)) {
|
||||
clearActiveRequestMissingTimer();
|
||||
} else if (activeRequestContext.allowMissingGrace) {
|
||||
} else if (
|
||||
shouldScheduleMissingActiveRequestGrace({
|
||||
allowMissingGrace: activeRequestContext.allowMissingGrace,
|
||||
agentRunPending: agentRunPendingRef.current,
|
||||
})
|
||||
) {
|
||||
// The backend can briefly report no active request between tool phases.
|
||||
// Confirm the absence before turning the UI idle, otherwise MindSpace
|
||||
// refreshes the page while tools are still mutating it.
|
||||
@@ -1062,6 +1084,7 @@ export function useTKMindChat(
|
||||
activeRequestMissingTimerRef.current = window.setTimeout(() => {
|
||||
activeRequestMissingTimerRef.current = null;
|
||||
if (activeRequestId.current !== rid) return;
|
||||
if (agentRunPendingRef.current) return;
|
||||
activeRequestId.current = null;
|
||||
setChatState('idle');
|
||||
setPendingTool(null);
|
||||
@@ -1139,6 +1162,7 @@ export function useTKMindChat(
|
||||
clearActiveRequestMissingTimer();
|
||||
setError(null);
|
||||
setPendingTool(null);
|
||||
agentRunPendingRef.current = false;
|
||||
activeRequestId.current = null;
|
||||
messagesRef.current = [];
|
||||
messageHistoryLoadedCountRef.current = 0;
|
||||
@@ -1173,6 +1197,7 @@ export function useTKMindChat(
|
||||
}
|
||||
setError(null);
|
||||
setPendingTool(null);
|
||||
agentRunPendingRef.current = false;
|
||||
activeRequestId.current = null;
|
||||
|
||||
let completed = false;
|
||||
@@ -1393,6 +1418,7 @@ export function useTKMindChat(
|
||||
connectTokenRef.current += 1;
|
||||
unsubscribeRef.current?.();
|
||||
clearActiveRequestMissingTimer();
|
||||
agentRunPendingRef.current = false;
|
||||
};
|
||||
// Re-run when the signed-in user changes so session storage stays per-user.
|
||||
}, [clearActiveRequestMissingTimer, ensureProvider, loadProjectMemory, notifyInsufficientBalance, refreshSessions, user?.id]);
|
||||
@@ -1529,6 +1555,8 @@ export function useTKMindChat(
|
||||
requestId,
|
||||
mindspaceContext: options?.mindspaceContext ?? null,
|
||||
});
|
||||
clearActiveRequestMissingTimer();
|
||||
agentRunPendingRef.current = true;
|
||||
const createdRun = await createAgentRun(
|
||||
activeSessionId,
|
||||
requestId,
|
||||
@@ -1587,6 +1615,7 @@ export function useTKMindChat(
|
||||
},
|
||||
});
|
||||
if (submitToken !== connectTokenRef.current) return;
|
||||
agentRunPendingRef.current = false;
|
||||
activeSessionId = finishedRun.sessionId;
|
||||
if (!activeSessionId) {
|
||||
throw new Error('后台任务已提交,但未返回会话');
|
||||
@@ -1697,6 +1726,7 @@ export function useTKMindChat(
|
||||
scheduleReplyRecoverySync(activeSessionId, submitToken);
|
||||
return;
|
||||
}
|
||||
agentRunPendingRef.current = false;
|
||||
if (session && activeSessionId) setSessions((prev) => touchSession(prev, activeSessionId!, -1));
|
||||
if (err instanceof ApiError && err.status === 402) {
|
||||
notifyInsufficientBalance();
|
||||
@@ -1728,6 +1758,7 @@ export function useTKMindChat(
|
||||
await cancelRequest(session.id, activeRequestId.current);
|
||||
} finally {
|
||||
clearActiveRequestMissingTimer();
|
||||
agentRunPendingRef.current = false;
|
||||
activeRequestId.current = null;
|
||||
setChatState('idle');
|
||||
}
|
||||
@@ -1762,6 +1793,7 @@ export function useTKMindChat(
|
||||
subscribedSessionIdRef.current = null;
|
||||
clearActiveRequestMissingTimer();
|
||||
clearStoredSessionId(userRef.current?.id);
|
||||
agentRunPendingRef.current = false;
|
||||
activeRequestId.current = null;
|
||||
messagesRef.current = [];
|
||||
messageHistoryLoadedCountRef.current = 0;
|
||||
|
||||
Reference in New Issue
Block a user