feat: improve mindspace asset handling and local runtime paths

This commit is contained in:
john
2026-06-28 12:18:26 +08:00
parent 4a9bc710f1
commit ea19ffb5fa
36 changed files with 867 additions and 100 deletions
+10 -1
View File
@@ -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;
+45 -4
View File
@@ -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 () => {