feat: improve mindspace asset handling and local runtime paths
This commit is contained in:
@@ -276,9 +276,17 @@ export function usePageEditSubChat({
|
||||
);
|
||||
|
||||
const submit = useCallback(
|
||||
async (text: string, context: MindSpaceChatContext, imageUrls?: string[]) => {
|
||||
async (
|
||||
text: string,
|
||||
context: MindSpaceChatContext,
|
||||
imageUrls?: string[],
|
||||
previewImageUrls?: string[],
|
||||
) => {
|
||||
const currentSession = sessionRef.current;
|
||||
const normalizedImageUrls = (imageUrls ?? []).filter((value) => typeof value === 'string' && value.trim());
|
||||
const normalizedPreviewImageUrls = (previewImageUrls ?? []).filter(
|
||||
(value) => typeof value === 'string' && value.trim(),
|
||||
);
|
||||
if (!currentSession || (!text.trim() && normalizedImageUrls.length === 0)) return;
|
||||
if (chatState === 'streaming' || chatState === 'loading' || chatState === 'connecting') return;
|
||||
|
||||
@@ -290,6 +298,7 @@ export function usePageEditSubChat({
|
||||
agentText: `${agentPrefix}${trimmed}`,
|
||||
displayText: trimmed,
|
||||
imageUrls: normalizedImageUrls,
|
||||
previewImageUrls: normalizedPreviewImageUrls,
|
||||
});
|
||||
const requestId = crypto.randomUUID();
|
||||
activeRequestId.current = requestId;
|
||||
|
||||
@@ -56,7 +56,6 @@ import {
|
||||
normalizeConversationMessages,
|
||||
getDisplayText,
|
||||
getToolConfirmation,
|
||||
getVisibleText,
|
||||
isCreditsExhaustedNotification,
|
||||
isRelayServerErrorMessage,
|
||||
pushMessage,
|
||||
@@ -69,9 +68,15 @@ import {
|
||||
} from '../utils/sessions';
|
||||
|
||||
const INSUFFICIENT_BALANCE_NOTICE = '余额不足,请充值后继续使用';
|
||||
const REPLY_RECOVERY_SYNC_DELAYS_MS = [1500, 5000, 12000];
|
||||
|
||||
export { INSUFFICIENT_BALANCE_NOTICE };
|
||||
|
||||
function isAmbiguousReplySubmitError(err: unknown) {
|
||||
if (!(err instanceof ApiError)) return true;
|
||||
return err.status === 0 || err.status === 409 || err.status >= 500;
|
||||
}
|
||||
|
||||
export function useTKMindChat(
|
||||
user?: PortalUser | null,
|
||||
onUserUpdate?: (user: PortalUser) => void,
|
||||
@@ -666,6 +671,7 @@ export function useTKMindChat(
|
||||
|
||||
const previousSessionId = readStoredSessionId(userRef.current?.id);
|
||||
let staleSession = false;
|
||||
let restorableSessionId: string | null = null;
|
||||
|
||||
if (previousSessionId) {
|
||||
try {
|
||||
@@ -676,8 +682,10 @@ export function useTKMindChat(
|
||||
} catch {
|
||||
// Best-effort cleanup: a failed delete should not block the next fresh chat.
|
||||
}
|
||||
clearStoredSessionId(userRef.current?.id);
|
||||
} else {
|
||||
restorableSessionId = previousSessionId;
|
||||
}
|
||||
clearStoredSessionId(userRef.current?.id);
|
||||
} catch (err) {
|
||||
if (err instanceof ApiError && (err.status === 403 || err.status === 404 || err.status === 400)) {
|
||||
clearStoredSessionId(userRef.current?.id);
|
||||
@@ -693,7 +701,12 @@ export function useTKMindChat(
|
||||
}
|
||||
|
||||
if (cancelled) return;
|
||||
setChatState('idle');
|
||||
if (restorableSessionId) {
|
||||
await connectSessionRef.current(restorableSessionId, { showLoading: false });
|
||||
if (cancelled) return;
|
||||
} else {
|
||||
setChatState('idle');
|
||||
}
|
||||
void refreshSessions();
|
||||
} catch (err) {
|
||||
if (!cancelled) {
|
||||
@@ -756,8 +769,12 @@ export function useTKMindChat(
|
||||
text: string,
|
||||
options?: { mindspaceContext?: MindSpaceChatContext },
|
||||
imageUrls?: string[],
|
||||
previewImageUrls?: string[],
|
||||
) => {
|
||||
const normalizedImageUrls = (imageUrls ?? []).filter((value) => typeof value === 'string' && value.trim());
|
||||
const normalizedPreviewImageUrls = (previewImageUrls ?? []).filter(
|
||||
(value) => typeof value === 'string' && value.trim(),
|
||||
);
|
||||
if (!text.trim() && normalizedImageUrls.length === 0) return;
|
||||
if (chatState === 'streaming' || chatState === 'loading' || chatState === 'connecting') return;
|
||||
|
||||
@@ -772,6 +789,7 @@ export function useTKMindChat(
|
||||
agentText: `${agentPrefix}${trimmed}`,
|
||||
displayText: trimmed,
|
||||
imageUrls: normalizedImageUrls,
|
||||
previewImageUrls: normalizedPreviewImageUrls,
|
||||
});
|
||||
const requestId = crypto.randomUUID();
|
||||
activeRequestId.current = requestId;
|
||||
@@ -811,6 +829,19 @@ export function useTKMindChat(
|
||||
try {
|
||||
await sendReply(activeSessionId, requestId, userMessage);
|
||||
} catch (err) {
|
||||
if (isAmbiguousReplySubmitError(err)) {
|
||||
subscribeToSession(activeSessionId);
|
||||
setChatState('streaming');
|
||||
setError(null);
|
||||
for (const delay of REPLY_RECOVERY_SYNC_DELAYS_MS) {
|
||||
window.setTimeout(() => {
|
||||
if (sessionRef.current?.id === activeSessionId) {
|
||||
void syncSessionMessages(activeSessionId);
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (session) setSessions((prev) => touchSession(prev, activeSessionId!, -1));
|
||||
if (err instanceof ApiError && err.status === 402) {
|
||||
notifyInsufficientBalance();
|
||||
@@ -821,7 +852,17 @@ export function useTKMindChat(
|
||||
activeRequestId.current = null;
|
||||
}
|
||||
},
|
||||
[notifyInsufficientBalance, session, chatState, grantedSkills, subscribeToSession, ensureProvider, loadProjectMemory, refreshSessions],
|
||||
[
|
||||
notifyInsufficientBalance,
|
||||
session,
|
||||
chatState,
|
||||
grantedSkills,
|
||||
subscribeToSession,
|
||||
ensureProvider,
|
||||
loadProjectMemory,
|
||||
refreshSessions,
|
||||
syncSessionMessages,
|
||||
],
|
||||
);
|
||||
|
||||
const stop = useCallback(async () => {
|
||||
|
||||
Reference in New Issue
Block a user