mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-18 00:02:45 +00:00
Use short 8-char IDs for session entries
- Replace custom uuidv4() with native crypto.randomUUID() - Entry IDs use first 8 hex chars with collision checking - Session IDs stay full UUIDs (used in filenames) - ~0.01 collisions per 10k entries, retry handles it
This commit is contained in:
parent
77595b97f9
commit
95312e00bb
1 changed files with 21 additions and 19 deletions
|
|
@ -1,19 +1,11 @@
|
||||||
import type { AppMessage } from "@mariozechner/pi-agent-core";
|
import type { AppMessage } from "@mariozechner/pi-agent-core";
|
||||||
import { randomBytes } from "crypto";
|
import { randomUUID } from "crypto";
|
||||||
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
import { appendFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
||||||
import { join, resolve } from "path";
|
import { join, resolve } from "path";
|
||||||
import { getAgentDir as getDefaultAgentDir } from "../config.js";
|
import { getAgentDir as getDefaultAgentDir } from "../config.js";
|
||||||
|
|
||||||
export const CURRENT_SESSION_VERSION = 2;
|
export const CURRENT_SESSION_VERSION = 2;
|
||||||
|
|
||||||
function uuidv4(): string {
|
|
||||||
const bytes = randomBytes(16);
|
|
||||||
bytes[6] = (bytes[6] & 0x0f) | 0x40;
|
|
||||||
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
||||||
const hex = bytes.toString("hex");
|
|
||||||
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Session Header (metadata, not part of conversation tree)
|
// Session Header (metadata, not part of conversation tree)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
@ -154,7 +146,7 @@ export function migrateSessionEntries(entries: FileEntry[]): void {
|
||||||
|
|
||||||
// Add id/parentId to conversation entries
|
// Add id/parentId to conversation entries
|
||||||
const convEntry = entry as ConversationEntry;
|
const convEntry = entry as ConversationEntry;
|
||||||
convEntry.id = uuidv4();
|
convEntry.id = randomUUID();
|
||||||
convEntry.parentId = prevId;
|
convEntry.parentId = prevId;
|
||||||
prevId = convEntry.id;
|
prevId = convEntry.id;
|
||||||
|
|
||||||
|
|
@ -357,9 +349,19 @@ export class SessionManager {
|
||||||
private inMemoryEntries: FileEntry[] = [];
|
private inMemoryEntries: FileEntry[] = [];
|
||||||
|
|
||||||
// Tree structure (v2)
|
// Tree structure (v2)
|
||||||
private byId: Map<string, ConversationEntry> = new Map();
|
private byId: Map<string, SessionEntry> = new Map();
|
||||||
private leafId: string = "";
|
private leafId: string = "";
|
||||||
|
|
||||||
|
/** Generate a unique short ID (8 hex chars, collision-checked) */
|
||||||
|
private _generateId(): string {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
const id = randomUUID().slice(0, 8);
|
||||||
|
if (!this.byId.has(id)) return id;
|
||||||
|
}
|
||||||
|
// Fallback to full UUID if somehow we have collisions
|
||||||
|
return randomUUID();
|
||||||
|
}
|
||||||
|
|
||||||
private constructor(cwd: string, sessionDir: string, sessionFile: string | null, persist: boolean) {
|
private constructor(cwd: string, sessionDir: string, sessionFile: string | null, persist: boolean) {
|
||||||
this.cwd = cwd;
|
this.cwd = cwd;
|
||||||
this.sessionDir = sessionDir;
|
this.sessionDir = sessionDir;
|
||||||
|
|
@ -381,7 +383,7 @@ export class SessionManager {
|
||||||
if (existsSync(this.sessionFile)) {
|
if (existsSync(this.sessionFile)) {
|
||||||
this.inMemoryEntries = loadEntriesFromFile(this.sessionFile);
|
this.inMemoryEntries = loadEntriesFromFile(this.sessionFile);
|
||||||
const header = this.inMemoryEntries.find((e) => e.type === "session") as SessionHeader | undefined;
|
const header = this.inMemoryEntries.find((e) => e.type === "session") as SessionHeader | undefined;
|
||||||
this.sessionId = header?.id ?? uuidv4();
|
this.sessionId = header?.id ?? randomUUID();
|
||||||
|
|
||||||
// Migrate v1 to v2 if needed
|
// Migrate v1 to v2 if needed
|
||||||
const version = header?.version ?? 1;
|
const version = header?.version ?? 1;
|
||||||
|
|
@ -398,7 +400,7 @@ export class SessionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _initNewSession(): void {
|
private _initNewSession(): void {
|
||||||
this.sessionId = uuidv4();
|
this.sessionId = randomUUID();
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = new Date().toISOString();
|
||||||
const header: SessionHeader = {
|
const header: SessionHeader = {
|
||||||
type: "session",
|
type: "session",
|
||||||
|
|
@ -488,7 +490,7 @@ export class SessionManager {
|
||||||
saveMessage(message: AppMessage): string {
|
saveMessage(message: AppMessage): string {
|
||||||
const entry: SessionMessageEntry = {
|
const entry: SessionMessageEntry = {
|
||||||
type: "message",
|
type: "message",
|
||||||
id: uuidv4(),
|
id: this._generateId(),
|
||||||
parentId: this.leafId || null,
|
parentId: this.leafId || null,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
message,
|
message,
|
||||||
|
|
@ -500,7 +502,7 @@ export class SessionManager {
|
||||||
saveThinkingLevelChange(thinkingLevel: string): string {
|
saveThinkingLevelChange(thinkingLevel: string): string {
|
||||||
const entry: ThinkingLevelChangeEntry = {
|
const entry: ThinkingLevelChangeEntry = {
|
||||||
type: "thinking_level_change",
|
type: "thinking_level_change",
|
||||||
id: uuidv4(),
|
id: this._generateId(),
|
||||||
parentId: this.leafId || null,
|
parentId: this.leafId || null,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
thinkingLevel,
|
thinkingLevel,
|
||||||
|
|
@ -512,7 +514,7 @@ export class SessionManager {
|
||||||
saveModelChange(provider: string, modelId: string): string {
|
saveModelChange(provider: string, modelId: string): string {
|
||||||
const entry: ModelChangeEntry = {
|
const entry: ModelChangeEntry = {
|
||||||
type: "model_change",
|
type: "model_change",
|
||||||
id: uuidv4(),
|
id: this._generateId(),
|
||||||
parentId: this.leafId || null,
|
parentId: this.leafId || null,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
provider,
|
provider,
|
||||||
|
|
@ -525,7 +527,7 @@ export class SessionManager {
|
||||||
saveCompaction(summary: string, firstKeptEntryId: string, tokensBefore: number): string {
|
saveCompaction(summary: string, firstKeptEntryId: string, tokensBefore: number): string {
|
||||||
const entry: CompactionEntry = {
|
const entry: CompactionEntry = {
|
||||||
type: "compaction",
|
type: "compaction",
|
||||||
id: uuidv4(),
|
id: this._generateId(),
|
||||||
parentId: this.leafId || null,
|
parentId: this.leafId || null,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
summary,
|
summary,
|
||||||
|
|
@ -603,7 +605,7 @@ export class SessionManager {
|
||||||
this.leafId = branchFromId;
|
this.leafId = branchFromId;
|
||||||
const entry: BranchSummaryEntry = {
|
const entry: BranchSummaryEntry = {
|
||||||
type: "branch_summary",
|
type: "branch_summary",
|
||||||
id: uuidv4(),
|
id: this._generateId(),
|
||||||
parentId: branchFromId,
|
parentId: branchFromId,
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
summary,
|
summary,
|
||||||
|
|
@ -613,7 +615,7 @@ export class SessionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
createBranchedSessionFromEntries(entries: FileEntry[], branchBeforeIndex: number): string | null {
|
createBranchedSessionFromEntries(entries: FileEntry[], branchBeforeIndex: number): string | null {
|
||||||
const newSessionId = uuidv4();
|
const newSessionId = randomUUID();
|
||||||
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
||||||
const newSessionFile = join(this.getSessionDir(), `${timestamp}_${newSessionId}.jsonl`);
|
const newSessionFile = join(this.getSessionDir(), `${timestamp}_${newSessionId}.jsonl`);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue