feat(kilo-vscode): migrate legacy sessions into new extension#7924
feat(kilo-vscode): migrate legacy sessions into new extension#7924imanolmzd-svg merged 63 commits intomainfrom
Conversation
…indexing Move the role filter from inside `parseParts` to `parsePartsFromConversation` so that message indices are derived only from the filtered list. This ensures part message IDs stay aligned with the imported messages and skipped entries (e.g. system role) do not cause index gaps in the generated IDs.
SummaryOverall this is solid work. The architecture is well-structured with clean separation between parsing, orchestration, and backend insertion. The deterministic ID scheme and upsert-everywhere approach make the migration idempotent, which is the right call for a feature like this. Below are the issues I found, ordered roughly by severity. Bugs / Correctness Issues1. Conversation file is read twice per session (P2)File: const messages = await createMessages(id, dir, item)
const parts = await createParts(id, dir, item)Both Recommendation: Read and parse the file once in 2.
|
Prefix all migrated entity IDs (sessions, messages, parts) with a `_migrated_` segment so they are clearly distinguishable from IDs produced by the regular runtime. Updates tests to assert the new prefix format.
…rseSession` Remove the intermediate `createMessages` and `createParts` async wrappers that each independently read and parsed the conversation file. The file is now fetched and parsed once in `parseSession`, with the resulting conversation passed directly to `parseMessagesFromConversation` and `parsePartsFromConversation`, eliminating redundant I/O.
…ectly `toTextWithinMessage` was a duplicate of `toText` with identical behavior. Replace all call sites with `toText` and delete the redundant function.
…asoning entry exists Guard `isProviderSpecificReasoning` with `!isReasoning` to prevent duplicate reasoning parts when an entry carries both a `type: "reasoning"` field and a provider-specific reasoning field (e.g. `reasoning_content`). The explicit reasoning entry takes precedence.
…s parsing Add unit tests for two previously uncovered scenarios: - Task block extraction: verify only the content inside `<task>` tags is kept when text exists outside the legacy task wrapper - Empty tool result: verify the tool name is used as fallback output when `tool_result` carries no readable text content Also replace the dynamic `FileType.Directory` workaround with the direct `vscode.FileType.Directory` enum reference, and harden `parseFile` to throw on non-array JSON instead of silently returning an empty array.
|
The error handling changes will be sent as a separate PR @markijbema |
|
@imanolmzd-svg Can you confirm that this is reversible for users? We do not risk any data loss with this migration? |
|
@marius-kilocode A few things: There's an option to delete legacy settings that is currently not shown because of a bug. In the migration error handling PR that I'm preparing, it shows fine. Still, I'm commenting it out so that we don't delete legacy settings, at least for now. We don't risk data loss from old sessions, but we do store a list of sessions successfully migrated. If they run the migration wizard again, they won't be able to reinsert those conversations. Thinking about it, I should remove that check, so session migration can be reattempted. There are other checks in place that prevent inserting duplicates. So that way we don't insert duplicates but the migration can be attempted more than once. I'll update the code |
… state Drop the `readSessionsToMigrate` filter and the post-migration `globalState` flag that tracked which sessions had already been migrated. Detection now returns all sessions found in global storage without filtering by prior migration status.
Check for an existing session row before inserting and return a `skipped: true` flag when the session already exists. The migration client honours this flag to bypass message and part imports, avoiding redundant work when migration is re-run. Replace `onConflictDoUpdate` with `onConflictDoNothing` on the session insert path to align with the new pre-check behaviour. Propagate the optional `skipped` field through the result types and generated SDK types for project, session, message, and part responses.
Tag text parts whose content begins with `[ERROR]` with `ignored: true` and a `legacy-system-error` metadata source. Introduces a new `isLegacySystemErrorText` utility in `parts-util` to encapsulate the detection logic.
… visible parts Parse `<feedback>` tags embedded in `tool_result` content and emit a dedicated text part so user feedback is surfaced as a visible message rather than buried inside tool result data. Introduces `getFeedbackText` utility to extract and trim the inner content of `<feedback>` blocks from arbitrary input.
| { throwOnError: true }, | ||
| ) | ||
| // Skip child imports when the session already exists so rerunning migration only imports missing sessions. | ||
| if (session.data?.skipped) { |
There was a problem hiding this comment.
WARNING: Retrying a partially imported session now stops too early
If a previous migration managed to insert the session row and then failed while importing message or part records, this branch returns success on every retry and never backfills the missing children. Before this change the per-row upserts made retries self-healing; now a transient failure can leave the migrated conversation permanently incomplete unless the existing session row is deleted first.

Context
Implementation
Backend:
project,session,message, andpartunder the Kilo routes to minimize upstream merge conflicts.Frontend:
projectIDwhen inserting the migrated session.Session parsing:
attempt_completionvisible as normal assistant text, so some final completion content may appear duplicated for now.Out of Scope
ui_messages.jsonare not migrated yet.Video/Screenshots
https://github.com/user-attachments/assets/2d20ffb9-ad59-4865-bc5b-47e2fea73efd
Testing
bun testfor the new legacy migration unit tests inpackages/kilo-vscode/tests/unit/legacy-migration/.bun run formatinpackages/kilo-vscode.bun run typecheckinpackages/kilo-vscode.kilo.db, appear in the correct project when the canonical project id is reused, and can be continued in the new extension.Fixes after review feedback