fix: repair chat history from DB when Goose session has empty placeholders
Portal direct chat → goosed escalation can leave hollow Goose messages while h5_conversation_messages retains the full dialogue. Backfill session detail from DB, extend snapshot list fallback, and keep stored session id on transient boot failures so refresh no longer looks like a blank new chat. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+25
-5
@@ -164,6 +164,7 @@ import { createFeedbackService } from './user-feedback.mjs';
|
||||
import { startScheduleReminderWorker } from './schedule-reminder-worker.mjs';
|
||||
import { createLlmProviderService, RELAY_BOOTSTRAP } from './llm-providers.mjs';
|
||||
import { createDirectChatService, isDirectChatSessionId, isPortalDirectChatSnapshot, sendDirectChatSessionEvents, shouldExpirePortalDirectChatSnapshot } from './direct-chat-service.mjs';
|
||||
import { repairSessionConversationFromDb } from './conversation-repair.mjs';
|
||||
import { createManagedChatIntentRouter } from './chat-intent-router.mjs';
|
||||
import { createSessionSnapshotService } from './session-snapshot.mjs';
|
||||
import { createConversationMemoryService } from './conversation-memory.mjs';
|
||||
@@ -1888,7 +1889,7 @@ async function ensureUserMemoryCapability(req, res) {
|
||||
return capabilityState;
|
||||
}
|
||||
|
||||
async function loadUserVisibleConversation(sessionId) {
|
||||
async function loadUserVisibleConversation(sessionId, userId) {
|
||||
const target = await tkmindProxy.resolveTarget(sessionId);
|
||||
const upstream = await tkmindProxy.apiFetchTo(target, `/sessions/${encodeURIComponent(sessionId)}`, {
|
||||
method: 'GET',
|
||||
@@ -1897,7 +1898,10 @@ async function loadUserVisibleConversation(sessionId) {
|
||||
const message = await upstream.text().catch(() => '');
|
||||
throw new Error(message || '读取会话失败');
|
||||
}
|
||||
const session = await upstream.json();
|
||||
let session = await upstream.json();
|
||||
if (authPool && userId) {
|
||||
session = await repairSessionConversationFromDb(authPool, session, sessionId, userId);
|
||||
}
|
||||
return (session?.conversation ?? []).filter((message) => message?.metadata?.userVisible);
|
||||
}
|
||||
|
||||
@@ -1928,7 +1932,7 @@ api.post('/user-memory/v1/remember-recent', async (req, res) => {
|
||||
}
|
||||
|
||||
try {
|
||||
const messages = await loadUserVisibleConversation(sessionId);
|
||||
const messages = await loadUserVisibleConversation(sessionId, req.currentUser.id);
|
||||
const result = await memoryV2.write({
|
||||
userId: req.currentUser.id,
|
||||
sessionId,
|
||||
@@ -4469,11 +4473,19 @@ api.get('/sessions/:sessionId', async (req, res, next) => {
|
||||
req.currentUser,
|
||||
);
|
||||
// Cache hit — reconstruct a Goose-compatible session response.
|
||||
const cachedGooseSession = {
|
||||
let cachedGooseSession = {
|
||||
...snapshot.session,
|
||||
// Embed only userVisible messages so getSession callers still work.
|
||||
conversation: sanitizedMessages,
|
||||
};
|
||||
if (authPool) {
|
||||
cachedGooseSession = await repairSessionConversationFromDb(
|
||||
authPool,
|
||||
cachedGooseSession,
|
||||
sessionId,
|
||||
req.currentUser.id,
|
||||
);
|
||||
}
|
||||
return res.json(cachedGooseSession);
|
||||
}
|
||||
}
|
||||
@@ -4494,13 +4506,21 @@ api.get('/sessions/:sessionId', async (req, res, next) => {
|
||||
const text = await upstream.text().catch(() => '');
|
||||
return res.status(upstream.status).send(text);
|
||||
}
|
||||
const gooseSession = await upstream.json();
|
||||
let gooseSession = await upstream.json();
|
||||
if (Array.isArray(gooseSession.conversation)) {
|
||||
gooseSession.conversation = sanitizeSessionConversationPublicHtmlLinks(
|
||||
gooseSession.conversation,
|
||||
req.currentUser,
|
||||
);
|
||||
}
|
||||
if (authPool) {
|
||||
gooseSession = await repairSessionConversationFromDb(
|
||||
authPool,
|
||||
gooseSession,
|
||||
sessionId,
|
||||
req.currentUser.id,
|
||||
);
|
||||
}
|
||||
// Write-through: persist snapshot async, don't block the response.
|
||||
if (sessionSnapshotService?.isEnabled()) {
|
||||
const messages = (gooseSession.conversation ?? [])
|
||||
|
||||
Reference in New Issue
Block a user