fix: delete transcripts on role ordering reset
This commit is contained in:
@@ -3,6 +3,7 @@ import { tmpdir } from "node:os";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { describe, expect, it, vi } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import type { SessionEntry } from "../../config/sessions.js";
|
import type { SessionEntry } from "../../config/sessions.js";
|
||||||
|
import * as sessions from "../../config/sessions.js";
|
||||||
import type { TypingMode } from "../../config/types.js";
|
import type { TypingMode } from "../../config/types.js";
|
||||||
import type { TemplateContext } from "../templating.js";
|
import type { TemplateContext } from "../templating.js";
|
||||||
import type { GetReplyOptions } from "../types.js";
|
import type { GetReplyOptions } from "../types.js";
|
||||||
@@ -127,11 +128,14 @@ describe("runReplyAgent typing (heartbeat)", () => {
|
|||||||
try {
|
try {
|
||||||
const sessionId = "session";
|
const sessionId = "session";
|
||||||
const storePath = path.join(stateDir, "sessions", "sessions.json");
|
const storePath = path.join(stateDir, "sessions", "sessions.json");
|
||||||
const sessionEntry = { sessionId, updatedAt: Date.now() };
|
const transcriptPath = sessions.resolveSessionTranscriptPath(sessionId);
|
||||||
|
const sessionEntry = { sessionId, updatedAt: Date.now(), sessionFile: transcriptPath };
|
||||||
const sessionStore = { main: sessionEntry };
|
const sessionStore = { main: sessionEntry };
|
||||||
|
|
||||||
await fs.mkdir(path.dirname(storePath), { recursive: true });
|
await fs.mkdir(path.dirname(storePath), { recursive: true });
|
||||||
await fs.writeFile(storePath, JSON.stringify(sessionStore), "utf-8");
|
await fs.writeFile(storePath, JSON.stringify(sessionStore), "utf-8");
|
||||||
|
await fs.mkdir(path.dirname(transcriptPath), { recursive: true });
|
||||||
|
await fs.writeFile(transcriptPath, "ok", "utf-8");
|
||||||
|
|
||||||
runEmbeddedPiAgentMock
|
runEmbeddedPiAgentMock
|
||||||
.mockImplementationOnce(async () => {
|
.mockImplementationOnce(async () => {
|
||||||
@@ -175,11 +179,14 @@ describe("runReplyAgent typing (heartbeat)", () => {
|
|||||||
try {
|
try {
|
||||||
const sessionId = "session";
|
const sessionId = "session";
|
||||||
const storePath = path.join(stateDir, "sessions", "sessions.json");
|
const storePath = path.join(stateDir, "sessions", "sessions.json");
|
||||||
const sessionEntry = { sessionId, updatedAt: Date.now() };
|
const transcriptPath = sessions.resolveSessionTranscriptPath(sessionId);
|
||||||
|
const sessionEntry = { sessionId, updatedAt: Date.now(), sessionFile: transcriptPath };
|
||||||
const sessionStore = { main: sessionEntry };
|
const sessionStore = { main: sessionEntry };
|
||||||
|
|
||||||
await fs.mkdir(path.dirname(storePath), { recursive: true });
|
await fs.mkdir(path.dirname(storePath), { recursive: true });
|
||||||
await fs.writeFile(storePath, JSON.stringify(sessionStore), "utf-8");
|
await fs.writeFile(storePath, JSON.stringify(sessionStore), "utf-8");
|
||||||
|
await fs.mkdir(path.dirname(transcriptPath), { recursive: true });
|
||||||
|
await fs.writeFile(transcriptPath, "ok", "utf-8");
|
||||||
|
|
||||||
runEmbeddedPiAgentMock
|
runEmbeddedPiAgentMock
|
||||||
.mockImplementationOnce(async () => ({
|
.mockImplementationOnce(async () => ({
|
||||||
@@ -229,11 +236,14 @@ describe("runReplyAgent typing (heartbeat)", () => {
|
|||||||
try {
|
try {
|
||||||
const sessionId = "session";
|
const sessionId = "session";
|
||||||
const storePath = path.join(stateDir, "sessions", "sessions.json");
|
const storePath = path.join(stateDir, "sessions", "sessions.json");
|
||||||
const sessionEntry = { sessionId, updatedAt: Date.now() };
|
const transcriptPath = sessions.resolveSessionTranscriptPath(sessionId);
|
||||||
|
const sessionEntry = { sessionId, updatedAt: Date.now(), sessionFile: transcriptPath };
|
||||||
const sessionStore = { main: sessionEntry };
|
const sessionStore = { main: sessionEntry };
|
||||||
|
|
||||||
await fs.mkdir(path.dirname(storePath), { recursive: true });
|
await fs.mkdir(path.dirname(storePath), { recursive: true });
|
||||||
await fs.writeFile(storePath, JSON.stringify(sessionStore), "utf-8");
|
await fs.writeFile(storePath, JSON.stringify(sessionStore), "utf-8");
|
||||||
|
await fs.mkdir(path.dirname(transcriptPath), { recursive: true });
|
||||||
|
await fs.writeFile(transcriptPath, "ok", "utf-8");
|
||||||
|
|
||||||
runEmbeddedPiAgentMock.mockImplementationOnce(async () => ({
|
runEmbeddedPiAgentMock.mockImplementationOnce(async () => ({
|
||||||
payloads: [{ text: "Message ordering conflict - please try again.", isError: true }],
|
payloads: [{ text: "Message ordering conflict - please try again.", isError: true }],
|
||||||
@@ -260,6 +270,7 @@ describe("runReplyAgent typing (heartbeat)", () => {
|
|||||||
});
|
});
|
||||||
expect(payload.text?.toLowerCase()).toContain("reset");
|
expect(payload.text?.toLowerCase()).toContain("reset");
|
||||||
expect(sessionStore.main.sessionId).not.toBe(sessionId);
|
expect(sessionStore.main.sessionId).not.toBe(sessionId);
|
||||||
|
await expect(fs.access(transcriptPath)).rejects.toBeDefined();
|
||||||
|
|
||||||
const persisted = JSON.parse(await fs.readFile(storePath, "utf-8"));
|
const persisted = JSON.parse(await fs.readFile(storePath, "utf-8"));
|
||||||
expect(persisted.main.sessionId).toBe(sessionStore.main.sessionId);
|
expect(persisted.main.sessionId).toBe(sessionStore.main.sessionId);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
|
import fs from "node:fs";
|
||||||
import { setCliSessionId } from "../../agents/cli-session.js";
|
import { setCliSessionId } from "../../agents/cli-session.js";
|
||||||
import { lookupContextTokens } from "../../agents/context.js";
|
import { lookupContextTokens } from "../../agents/context.js";
|
||||||
import { DEFAULT_CONTEXT_TOKENS } from "../../agents/defaults.js";
|
import { DEFAULT_CONTEXT_TOKENS } from "../../agents/defaults.js";
|
||||||
@@ -8,6 +9,7 @@ import { queueEmbeddedPiMessage } from "../../agents/pi-embedded.js";
|
|||||||
import { hasNonzeroUsage } from "../../agents/usage.js";
|
import { hasNonzeroUsage } from "../../agents/usage.js";
|
||||||
import {
|
import {
|
||||||
resolveAgentIdFromSessionKey,
|
resolveAgentIdFromSessionKey,
|
||||||
|
resolveSessionFilePath,
|
||||||
resolveSessionTranscriptPath,
|
resolveSessionTranscriptPath,
|
||||||
type SessionEntry,
|
type SessionEntry,
|
||||||
updateSessionStore,
|
updateSessionStore,
|
||||||
@@ -247,6 +249,8 @@ export async function runReplyAgent(params: {
|
|||||||
};
|
};
|
||||||
const resetSessionAfterRoleOrderingConflict = async (reason: string): Promise<boolean> => {
|
const resetSessionAfterRoleOrderingConflict = async (reason: string): Promise<boolean> => {
|
||||||
if (!sessionKey || !activeSessionStore || !storePath) return false;
|
if (!sessionKey || !activeSessionStore || !storePath) return false;
|
||||||
|
const prevEntry = activeSessionStore[sessionKey] ?? activeSessionEntry;
|
||||||
|
const prevSessionId = prevEntry?.sessionId;
|
||||||
const nextSessionId = crypto.randomUUID();
|
const nextSessionId = crypto.randomUUID();
|
||||||
const nextEntry: SessionEntry = {
|
const nextEntry: SessionEntry = {
|
||||||
...(activeSessionStore[sessionKey] ?? activeSessionEntry),
|
...(activeSessionStore[sessionKey] ?? activeSessionEntry),
|
||||||
@@ -279,6 +283,19 @@ export async function runReplyAgent(params: {
|
|||||||
defaultRuntime.error(
|
defaultRuntime.error(
|
||||||
`Role ordering conflict (${reason}). Restarting session ${sessionKey} -> ${nextSessionId}.`,
|
`Role ordering conflict (${reason}). Restarting session ${sessionKey} -> ${nextSessionId}.`,
|
||||||
);
|
);
|
||||||
|
if (prevSessionId) {
|
||||||
|
const transcriptCandidates = new Set<string>();
|
||||||
|
const resolved = resolveSessionFilePath(prevSessionId, prevEntry, { agentId });
|
||||||
|
if (resolved) transcriptCandidates.add(resolved);
|
||||||
|
transcriptCandidates.add(resolveSessionTranscriptPath(prevSessionId, agentId));
|
||||||
|
for (const candidate of transcriptCandidates) {
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(candidate);
|
||||||
|
} catch {
|
||||||
|
// Best-effort cleanup.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user