Add automatic session migration when switching from SDK to Native mode
Some checks failed
Release Binaries / release (push) Has been cancelled

This commit is contained in:
Gemini AI
2025-12-27 11:13:43 +04:00
Unverified
parent eaf93e2924
commit 64c7fb8d47
6 changed files with 311 additions and 0 deletions

View File

@@ -165,6 +165,34 @@ export const nativeSessionApi = {
return data.messages
},
/**
* Import sessions from SDK mode to Native mode
*/
async importSessions(workspaceId: string, sessions: Array<{
id: string
title?: string
parentId?: string | null
createdAt?: number
updatedAt?: number
model?: { providerId: string; modelId: string }
agent?: string
messages?: Array<{
id: string
role: "user" | "assistant" | "system" | "tool"
content?: string
createdAt?: number
}>
}>): Promise<{ success: boolean; imported: number; skipped: number }> {
const response = await fetch(`${CODENOMAD_API_BASE}/api/native/workspaces/${encodeURIComponent(workspaceId)}/sessions/import`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ sessions })
})
if (!response.ok) throw new Error("Failed to import sessions")
return response.json()
},
/**
* Send a prompt to the session and get a streaming response
*/

View File

@@ -3,6 +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 { preferences, setAgentModelPreference, getAgentModelPreference } from "./preferences"
import { setSessionCompactionState } from "./session-compaction"
import {
@@ -389,6 +390,26 @@ async function fetchSessions(instanceId: string): Promise<void> {
let responseData: any[] = []
if (isNative) {
// Check if we need to migrate sessions from SDK mode
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)
}
}
const nativeSessions = await nativeSessionApi.listSessions(instanceId)
responseData = nativeSessions.map(s => ({
id: s.id,

View File

@@ -0,0 +1,125 @@
/**
* Session Migration - Handles importing sessions when switching between SDK and Native modes
*/
import { nativeSessionApi } from "../lib/lite-mode"
import { sessions } from "./session-state"
import { getLogger } from "../lib/logger"
import type { Session } from "../types/session"
const log = getLogger("session-migration")
// Track which workspaces have already been migrated to prevent duplicate migrations
const migratedWorkspaces = new Set<string>()
export interface MigrationResult {
success: boolean
imported: number
skipped: number
error?: string
}
/**
* Check if a workspace needs session migration
*/
export function needsMigration(workspaceId: string): boolean {
return !migratedWorkspaces.has(workspaceId)
}
/**
* Mark a workspace as migrated
*/
export function markMigrated(workspaceId: string): void {
migratedWorkspaces.add(workspaceId)
}
/**
* Get existing SDK sessions for a workspace from the local store
*/
export function getExistingSdkSessions(instanceId: string): Session[] {
const instanceSessions = sessions().get(instanceId)
if (!instanceSessions) return []
return Array.from(instanceSessions.values())
}
/**
* Migrate sessions from SDK mode to Native mode
* This should be called when the user switches from an SDK binary to native mode
*/
export async function migrateSessionsToNative(
workspaceId: string,
sdkSessions: Array<{
id: string
title?: string
parentId?: string | null
time?: { created?: number; updated?: number }
model?: { providerId: string; modelId: string }
agent?: string
messages?: Array<{
id: string
role: "user" | "assistant" | "system" | "tool"
content?: string
timestamp?: number
}>
}>
): Promise<MigrationResult> {
if (sdkSessions.length === 0) {
log.info({ workspaceId }, "No sessions to migrate")
markMigrated(workspaceId)
return { success: true, imported: 0, skipped: 0 }
}
try {
log.info({ workspaceId, count: sdkSessions.length }, "Starting session migration to native mode")
// Transform to the format expected by the native API
const sessionsToImport = sdkSessions.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,
messages: s.messages?.map(m => ({
id: m.id,
role: m.role,
content: m.content,
createdAt: m.timestamp
}))
}))
const result = await nativeSessionApi.importSessions(workspaceId, sessionsToImport)
log.info({ workspaceId, ...result }, "Session migration completed")
markMigrated(workspaceId)
return {
success: result.success,
imported: result.imported,
skipped: result.skipped
}
} catch (error) {
log.error({ workspaceId, error }, "Session migration failed")
return {
success: false,
imported: 0,
skipped: 0,
error: error instanceof Error ? error.message : String(error)
}
}
}
/**
* Clear migration status (for testing or when user explicitly wants to re-migrate)
*/
export function clearMigrationStatus(workspaceId: string): void {
migratedWorkspaces.delete(workspaceId)
}
/**
* Clear all migration statuses
*/
export function clearAllMigrationStatuses(): void {
migratedWorkspaces.clear()
}