fix: preserve transcript agent scope

This commit is contained in:
Peter Steinberger
2026-05-08 12:57:33 +01:00
parent 8fc499a71a
commit 7ce1e6b25d
2 changed files with 49 additions and 7 deletions

View File

@@ -153,6 +153,40 @@ describe("TranscriptSessionManager", () => {
});
});
it("preserves non-main agent scope for virtual sqlite branches and forks", async () => {
await makeTempSessionFile();
const sessionFile = createSqliteSessionTranscriptLocator({
agentId: "qa",
sessionId: "qa-source-session",
});
const sessionManager = openTranscriptSessionManager({
sessionFile,
sessionId: "qa-source-session",
cwd: "/tmp/qa-workspace",
});
const userId = sessionManager.appendMessage({
role: "user",
content: "qa source",
timestamp: 4,
});
const branchFile = sessionManager.createBranchedSession(userId);
expect(branchFile).toMatch(/^sqlite-transcript:\/\/qa\//);
expect(
resolveSqliteSessionTranscriptScopeForPath({ transcriptPath: branchFile! }),
).toMatchObject({
agentId: "qa",
});
const forked = SessionManager.forkFrom(sessionFile, "/tmp/qa-fork");
expect(forked.getSessionFile()).toMatch(/^sqlite-transcript:\/\/qa\//);
expect(
resolveSqliteSessionTranscriptScopeForPath({ transcriptPath: forked.getSessionFile()! }),
).toMatchObject({
agentId: "qa",
});
});
it("persists initial user messages synchronously before the first assistant message", async () => {
const sessionFile = await makeTempSessionFile();
const sessionManager = openTranscriptSessionManager({

View File

@@ -3,6 +3,7 @@ import path from "node:path";
import {
createSqliteSessionTranscriptLocator,
isSqliteSessionTranscriptLocator,
parseSqliteSessionTranscriptLocator,
} from "../../config/sessions/paths.js";
import {
appendSqliteSessionTranscriptEvent,
@@ -70,19 +71,26 @@ function resolveSessionDirForIdentifier(sessionFile: string, sessionDir?: string
return isSqliteSessionTranscriptLocator(sessionFile) ? "" : path.dirname(sessionFile);
}
function createSessionFileIdentifier(header: SessionHeader, sessionDir?: string): string {
function createSessionFileIdentifier(
header: SessionHeader,
sessionDir?: string,
agentId = DEFAULT_AGENT_ID,
): string {
const dir = sessionDir?.trim();
if (dir) {
return path.join(path.resolve(dir), createSessionFileName(header));
}
return createSqliteSessionTranscriptLocator({
agentId: DEFAULT_AGENT_ID,
agentId,
sessionId: header.id,
});
}
function resolveAgentIdFromSessionPath(sessionFile: string): string {
void sessionFile;
const locator = parseSqliteSessionTranscriptLocator(sessionFile);
if (locator) {
return locator.agentId;
}
return DEFAULT_AGENT_ID;
}
@@ -443,10 +451,10 @@ export class TranscriptSessionManager implements SessionManager {
cwd: targetCwd,
parentSession: sourceFile,
});
const sessionFile = createSessionFileIdentifier(header, sessionDir);
const sessionFile = createSessionFileIdentifier(header, sessionDir, sourceScope.agentId);
const state = new TranscriptState({ header, entries: sourceState.getEntries() });
const sqliteScope = {
agentId: resolveAgentIdFromSessionPath(sessionFile),
agentId: sourceScope.agentId,
sessionId: header.id,
transcriptPath: normalizeSessionFileIdentifier(sessionFile),
};
@@ -507,7 +515,7 @@ export class TranscriptSessionManager implements SessionManager {
this.sessionFile ??
(this.sessionDir
? path.join(this.sessionDir, createSessionFileName(header))
: createSessionFileIdentifier(header));
: createSessionFileIdentifier(header, undefined, this.sqliteScope?.agentId));
this.sqliteScope = {
agentId: resolveAgentIdFromSessionPath(this.sessionFile),
sessionId: header.id,
@@ -672,7 +680,7 @@ export class TranscriptSessionManager implements SessionManager {
const sessionFile = this.sessionDir
? path.join(this.sessionDir, `${timestamp}_${header.id}.jsonl`)
: createSqliteSessionTranscriptLocator({
agentId: DEFAULT_AGENT_ID,
agentId: this.sqliteScope?.agentId ?? DEFAULT_AGENT_ID,
sessionId: header.id,
});
if (!this.persist) {