Fix session migration: cache SDK sessions to localStorage for auto-import on native mode startup
Some checks failed
Release Binaries / release (push) Has been cancelled

This commit is contained in:
Gemini AI
2025-12-27 11:20:56 +04:00
Unverified
parent 64c7fb8d47
commit 6fe7367eff
2 changed files with 132 additions and 19 deletions

View File

@@ -3,7 +3,7 @@ import type { Message } from "../types/message"
import { instances } from "./instances" import { instances } from "./instances"
import { nativeSessionApi } from "../lib/lite-mode" import { nativeSessionApi } from "../lib/lite-mode"
import { needsMigration, migrateSessionsToNative, markMigrated, getExistingSdkSessions } from "./session-migration" import { needsMigration, autoImportCachedSessions, markMigrated, cacheSDKSessions } from "./session-migration"
import { preferences, setAgentModelPreference, getAgentModelPreference } from "./preferences" import { preferences, setAgentModelPreference, getAgentModelPreference } from "./preferences"
import { setSessionCompactionState } from "./session-compaction" import { setSessionCompactionState } from "./session-compaction"
import { import {
@@ -390,23 +390,16 @@ async function fetchSessions(instanceId: string): Promise<void> {
let responseData: any[] = [] let responseData: any[] = []
if (isNative) { if (isNative) {
// Check if we need to migrate sessions from SDK mode // Auto-import cached SDK sessions on native mode startup
if (needsMigration(instanceId)) { if (needsMigration(instanceId)) {
const existingSdkSessions = getExistingSdkSessions(instanceId) try {
if (existingSdkSessions.length > 0) { const result = await autoImportCachedSessions(instanceId)
log.info({ instanceId, count: existingSdkSessions.length }, "Migrating SDK sessions to native mode") if (result.imported > 0) {
const migrationData = existingSdkSessions.map(s => ({ log.info({ instanceId, result }, "Auto-imported SDK sessions to native mode")
id: s.id, }
title: s.title, } catch (error) {
parentId: s.parentId, log.error({ instanceId, error }, "Failed to auto-import SDK sessions")
time: s.time, markMigrated(instanceId) // Mark as migrated to prevent repeated failures
model: s.model,
agent: s.agent
}))
const result = await migrateSessionsToNative(instanceId, migrationData)
log.info({ instanceId, result }, "Migration completed")
} else {
markMigrated(instanceId)
} }
} }
@@ -488,6 +481,12 @@ async function fetchSessions(instanceId: string): Promise<void> {
return next return next
}) })
// Cache SDK sessions to localStorage for later migration to native mode
if (!isNative && sessionMap.size > 0) {
cacheSDKSessions(instanceId, Array.from(sessionMap.values()))
}
setMessagesLoaded((prev) => { setMessagesLoaded((prev) => {
const next = new Map(prev) const next = new Map(prev)
const loadedSet = next.get(instanceId) const loadedSet = next.get(instanceId)

View File

@@ -1,5 +1,8 @@
/** /**
* Session Migration - Handles importing sessions when switching between SDK and Native modes * Session Migration - Handles importing sessions when switching between SDK and Native modes
*
* This module caches SDK session data to localStorage so it can be imported to Native mode
* when the user switches modes.
*/ */
import { nativeSessionApi } from "../lib/lite-mode" import { nativeSessionApi } from "../lib/lite-mode"
@@ -9,9 +12,22 @@ import type { Session } from "../types/session"
const log = getLogger("session-migration") const log = getLogger("session-migration")
// LocalStorage key prefix for cached SDK sessions
const SDK_SESSION_CACHE_PREFIX = "nomadarch_sdk_sessions_"
// Track which workspaces have already been migrated to prevent duplicate migrations // Track which workspaces have already been migrated to prevent duplicate migrations
const migratedWorkspaces = new Set<string>() const migratedWorkspaces = new Set<string>()
export interface CachedSession {
id: string
title?: string
parentId?: string | null
createdAt?: number
updatedAt?: number
model?: { providerId: string; modelId: string }
agent?: string
}
export interface MigrationResult { export interface MigrationResult {
success: boolean success: boolean
imported: number imported: number
@@ -19,6 +35,63 @@ export interface MigrationResult {
error?: string error?: string
} }
/**
* Cache SDK sessions to localStorage for later migration
* This should be called whenever sessions are fetched in SDK mode
*/
export function cacheSDKSessions(workspaceId: string, sessionList: Session[]): void {
if (sessionList.length === 0) return
try {
const cached: CachedSession[] = sessionList.map(s => ({
id: s.id,
title: s.title,
parentId: s.parentId,
createdAt: s.time?.created,
updatedAt: s.time?.updated,
model: s.model,
agent: s.agent
}))
const key = SDK_SESSION_CACHE_PREFIX + workspaceId
localStorage.setItem(key, JSON.stringify(cached))
log.info({ workspaceId, count: cached.length }, "Cached SDK sessions for migration")
} catch (error) {
log.error({ workspaceId, error }, "Failed to cache SDK sessions")
}
}
/**
* Get cached SDK sessions from localStorage
*/
export function getCachedSDKSessions(workspaceId: string): CachedSession[] {
try {
const key = SDK_SESSION_CACHE_PREFIX + workspaceId
const cached = localStorage.getItem(key)
if (!cached) return []
const sessions = JSON.parse(cached) as CachedSession[]
log.info({ workspaceId, count: sessions.length }, "Retrieved cached SDK sessions")
return sessions
} catch (error) {
log.error({ workspaceId, error }, "Failed to retrieve cached SDK sessions")
return []
}
}
/**
* Clear cached SDK sessions after successful migration
*/
export function clearCachedSDKSessions(workspaceId: string): void {
try {
const key = SDK_SESSION_CACHE_PREFIX + workspaceId
localStorage.removeItem(key)
log.info({ workspaceId }, "Cleared cached SDK sessions")
} catch (error) {
log.error({ workspaceId, error }, "Failed to clear cached SDK sessions")
}
}
/** /**
* Check if a workspace needs session migration * Check if a workspace needs session migration
*/ */
@@ -52,6 +125,8 @@ export async function migrateSessionsToNative(
id: string id: string
title?: string title?: string
parentId?: string | null parentId?: string | null
createdAt?: number
updatedAt?: number
time?: { created?: number; updated?: number } time?: { created?: number; updated?: number }
model?: { providerId: string; modelId: string } model?: { providerId: string; modelId: string }
agent?: string agent?: string
@@ -77,8 +152,8 @@ export async function migrateSessionsToNative(
id: s.id, id: s.id,
title: s.title, title: s.title,
parentId: s.parentId, parentId: s.parentId,
createdAt: s.time?.created, createdAt: s.createdAt || s.time?.created,
updatedAt: s.time?.updated, updatedAt: s.updatedAt || s.time?.updated,
model: s.model, model: s.model,
agent: s.agent, agent: s.agent,
messages: s.messages?.map(m => ({ messages: s.messages?.map(m => ({
@@ -94,6 +169,11 @@ export async function migrateSessionsToNative(
log.info({ workspaceId, ...result }, "Session migration completed") log.info({ workspaceId, ...result }, "Session migration completed")
markMigrated(workspaceId) markMigrated(workspaceId)
// Clear the cache after successful migration
if (result.success) {
clearCachedSDKSessions(workspaceId)
}
return { return {
success: result.success, success: result.success,
imported: result.imported, imported: result.imported,
@@ -110,6 +190,40 @@ export async function migrateSessionsToNative(
} }
} }
/**
* Auto-import cached SDK sessions to native mode
* This is the main entry point for automatic migration on startup
*/
export async function autoImportCachedSessions(workspaceId: string): Promise<MigrationResult> {
if (!needsMigration(workspaceId)) {
return { success: true, imported: 0, skipped: 0 }
}
// Get cached sessions from localStorage
const cachedSessions = getCachedSDKSessions(workspaceId)
if (cachedSessions.length === 0) {
// Also check in-memory sessions as a fallback
const memorySessions = getExistingSdkSessions(workspaceId)
if (memorySessions.length > 0) {
const migrationData = memorySessions.map(s => ({
id: s.id,
title: s.title,
parentId: s.parentId,
time: s.time,
model: s.model,
agent: s.agent
}))
return migrateSessionsToNative(workspaceId, migrationData)
}
markMigrated(workspaceId)
return { success: true, imported: 0, skipped: 0 }
}
return migrateSessionsToNative(workspaceId, cachedSessions)
}
/** /**
* Clear migration status (for testing or when user explicitly wants to re-migrate) * Clear migration status (for testing or when user explicitly wants to re-migrate)
*/ */