mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 06:02:42 +00:00
Fix branch selector for single message and --no-session mode
- Allow branch selector to open with single user message (changed <= 1 to === 0 check) - Support in-memory branching for --no-session mode (no files created) - Add isEnabled() getter to SessionManager - Update sessionFile getter to return null when sessions disabled - Update SessionSwitchEvent types to allow null session files - Add branching tests for single message and --no-session scenarios fixes #163
This commit is contained in:
parent
09a48fd1c3
commit
3d35e7c469
10 changed files with 292 additions and 27 deletions
|
|
@ -76,7 +76,7 @@ export interface CompactionResult {
|
|||
|
||||
/** Session statistics for /session command */
|
||||
export interface SessionStats {
|
||||
sessionFile: string;
|
||||
sessionFile: string | null;
|
||||
sessionId: string;
|
||||
userMessages: number;
|
||||
assistantMessages: number;
|
||||
|
|
@ -320,9 +320,9 @@ export class AgentSession {
|
|||
return this.agent.getQueueMode();
|
||||
}
|
||||
|
||||
/** Current session file path */
|
||||
get sessionFile(): string {
|
||||
return this.sessionManager.getSessionFile();
|
||||
/** Current session file path, or null if sessions are disabled */
|
||||
get sessionFile(): string | null {
|
||||
return this.sessionManager.isEnabled() ? this.sessionManager.getSessionFile() : null;
|
||||
}
|
||||
|
||||
/** Current session ID */
|
||||
|
|
@ -966,11 +966,15 @@ export class AgentSession {
|
|||
return { selectedText, skipped: true };
|
||||
}
|
||||
|
||||
// Create branched session
|
||||
// Create branched session (returns null in --no-session mode)
|
||||
const newSessionFile = this.sessionManager.createBranchedSessionFromEntries(entries, entryIndex);
|
||||
this.sessionManager.setSessionFile(newSessionFile);
|
||||
|
||||
// Emit session_switch event
|
||||
// Update session file if we have one (file-based mode)
|
||||
if (newSessionFile !== null) {
|
||||
this.sessionManager.setSessionFile(newSessionFile);
|
||||
}
|
||||
|
||||
// Emit session_switch event (in --no-session mode, both files are null)
|
||||
if (this._hookRunner) {
|
||||
this._hookRunner.setSessionFile(newSessionFile);
|
||||
await this._hookRunner.emit({
|
||||
|
|
@ -981,7 +985,7 @@ export class AgentSession {
|
|||
});
|
||||
}
|
||||
|
||||
// Reload
|
||||
// Reload messages from entries (works for both file and in-memory mode)
|
||||
const loaded = loadSessionFromEntries(this.sessionManager.loadEntries());
|
||||
this.agent.replaceMessages(loaded.messages);
|
||||
|
||||
|
|
|
|||
|
|
@ -86,10 +86,10 @@ export interface SessionStartEvent {
|
|||
*/
|
||||
export interface SessionSwitchEvent {
|
||||
type: "session_switch";
|
||||
/** New session file path */
|
||||
newSessionFile: string;
|
||||
/** Previous session file path */
|
||||
previousSessionFile: string;
|
||||
/** New session file path, or null in --no-session mode */
|
||||
newSessionFile: string | null;
|
||||
/** Previous session file path, or null in --no-session mode */
|
||||
previousSessionFile: string | null;
|
||||
/** Reason for the switch */
|
||||
reason: "branch" | "switch";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,6 +231,11 @@ export class SessionManager {
|
|||
this.enabled = false;
|
||||
}
|
||||
|
||||
/** Check if session persistence is enabled */
|
||||
isEnabled(): boolean {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
private getSessionDirectory(): string {
|
||||
const cwd = process.cwd();
|
||||
// Replace all path separators and colons (for Windows drive letters) with dashes
|
||||
|
|
@ -637,32 +642,43 @@ export class SessionManager {
|
|||
/**
|
||||
* Create a branched session from session entries up to (but not including) a specific entry index.
|
||||
* This preserves compaction events and all entry types.
|
||||
* Returns the new session file path.
|
||||
* Returns the new session file path, or null if in --no-session mode (in-memory only).
|
||||
*/
|
||||
createBranchedSessionFromEntries(entries: SessionEntry[], branchBeforeIndex: number): string {
|
||||
createBranchedSessionFromEntries(entries: SessionEntry[], branchBeforeIndex: number): string | null {
|
||||
const newSessionId = uuidv4();
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
||||
const newSessionFile = join(this.sessionDir, `${timestamp}_${newSessionId}.jsonl`);
|
||||
|
||||
// Copy all entries up to (but not including) the branch point
|
||||
// Build new entries list (up to but not including branch point)
|
||||
const newEntries: SessionEntry[] = [];
|
||||
for (let i = 0; i < branchBeforeIndex; i++) {
|
||||
const entry = entries[i];
|
||||
|
||||
if (entry.type === "session") {
|
||||
// Rewrite session header with new ID and branchedFrom
|
||||
const newHeader: SessionHeader = {
|
||||
newEntries.push({
|
||||
...entry,
|
||||
id: newSessionId,
|
||||
timestamp: new Date().toISOString(),
|
||||
branchedFrom: this.sessionFile,
|
||||
};
|
||||
appendFileSync(newSessionFile, JSON.stringify(newHeader) + "\n");
|
||||
branchedFrom: this.enabled ? this.sessionFile : undefined,
|
||||
});
|
||||
} else {
|
||||
// Copy other entries as-is
|
||||
appendFileSync(newSessionFile, JSON.stringify(entry) + "\n");
|
||||
newEntries.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return newSessionFile;
|
||||
if (this.enabled) {
|
||||
// Write to file
|
||||
for (const entry of newEntries) {
|
||||
appendFileSync(newSessionFile, JSON.stringify(entry) + "\n");
|
||||
}
|
||||
return newSessionFile;
|
||||
} else {
|
||||
// In-memory mode: replace inMemoryEntries, no file created
|
||||
this.inMemoryEntries = newEntries;
|
||||
this.sessionId = newSessionId;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue