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
Some checks failed
Release Binaries / release (push) Has been cancelled
This commit is contained in:
@@ -3,7 +3,7 @@ import type { Message } from "../types/message"
|
||||
|
||||
import { instances } from "./instances"
|
||||
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 { setSessionCompactionState } from "./session-compaction"
|
||||
import {
|
||||
@@ -390,23 +390,16 @@ async function fetchSessions(instanceId: string): Promise<void> {
|
||||
let responseData: any[] = []
|
||||
|
||||
if (isNative) {
|
||||
// Check if we need to migrate sessions from SDK mode
|
||||
// Auto-import cached SDK sessions on native mode startup
|
||||
if (needsMigration(instanceId)) {
|
||||
const existingSdkSessions = getExistingSdkSessions(instanceId)
|
||||
if (existingSdkSessions.length > 0) {
|
||||
log.info({ instanceId, count: existingSdkSessions.length }, "Migrating SDK sessions to native mode")
|
||||
const migrationData = existingSdkSessions.map(s => ({
|
||||
id: s.id,
|
||||
title: s.title,
|
||||
parentId: s.parentId,
|
||||
time: s.time,
|
||||
model: s.model,
|
||||
agent: s.agent
|
||||
}))
|
||||
const result = await migrateSessionsToNative(instanceId, migrationData)
|
||||
log.info({ instanceId, result }, "Migration completed")
|
||||
} else {
|
||||
markMigrated(instanceId)
|
||||
try {
|
||||
const result = await autoImportCachedSessions(instanceId)
|
||||
if (result.imported > 0) {
|
||||
log.info({ instanceId, result }, "Auto-imported SDK sessions to native mode")
|
||||
}
|
||||
} catch (error) {
|
||||
log.error({ instanceId, error }, "Failed to auto-import SDK sessions")
|
||||
markMigrated(instanceId) // Mark as migrated to prevent repeated failures
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,6 +481,12 @@ async function fetchSessions(instanceId: string): Promise<void> {
|
||||
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) => {
|
||||
const next = new Map(prev)
|
||||
const loadedSet = next.get(instanceId)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
/**
|
||||
* 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"
|
||||
@@ -9,9 +12,22 @@ import type { Session } from "../types/session"
|
||||
|
||||
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
|
||||
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 {
|
||||
success: boolean
|
||||
imported: number
|
||||
@@ -19,6 +35,63 @@ export interface MigrationResult {
|
||||
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
|
||||
*/
|
||||
@@ -52,6 +125,8 @@ export async function migrateSessionsToNative(
|
||||
id: string
|
||||
title?: string
|
||||
parentId?: string | null
|
||||
createdAt?: number
|
||||
updatedAt?: number
|
||||
time?: { created?: number; updated?: number }
|
||||
model?: { providerId: string; modelId: string }
|
||||
agent?: string
|
||||
@@ -77,8 +152,8 @@ export async function migrateSessionsToNative(
|
||||
id: s.id,
|
||||
title: s.title,
|
||||
parentId: s.parentId,
|
||||
createdAt: s.time?.created,
|
||||
updatedAt: s.time?.updated,
|
||||
createdAt: s.createdAt || s.time?.created,
|
||||
updatedAt: s.updatedAt || s.time?.updated,
|
||||
model: s.model,
|
||||
agent: s.agent,
|
||||
messages: s.messages?.map(m => ({
|
||||
@@ -94,6 +169,11 @@ export async function migrateSessionsToNative(
|
||||
log.info({ workspaceId, ...result }, "Session migration completed")
|
||||
markMigrated(workspaceId)
|
||||
|
||||
// Clear the cache after successful migration
|
||||
if (result.success) {
|
||||
clearCachedSDKSessions(workspaceId)
|
||||
}
|
||||
|
||||
return {
|
||||
success: result.success,
|
||||
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)
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user