mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-11 04:48:05 +00:00
refactor: drop legacy transcript path builders
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
import path from "node:path";
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
|
||||
import type { ResolvedAgentRoute } from "openclaw/plugin-sdk/routing";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
@@ -55,7 +54,6 @@ const sessionMocks = vi.hoisted(() => {
|
||||
),
|
||||
recordSessionMetaFromInbound: vi.fn(),
|
||||
resolveAndPersistSessionFile: vi.fn(),
|
||||
resolveSessionTranscriptPath: vi.fn(),
|
||||
sessionStore,
|
||||
};
|
||||
});
|
||||
@@ -163,7 +161,6 @@ vi.mock("openclaw/plugin-sdk/session-store-runtime", async () => {
|
||||
getSessionEntry: sessionMocks.getSessionEntry,
|
||||
listSessionEntries: sessionMocks.listSessionEntries,
|
||||
resolveAndPersistSessionFile: sessionMocks.resolveAndPersistSessionFile,
|
||||
resolveSessionTranscriptPath: sessionMocks.resolveSessionTranscriptPath,
|
||||
};
|
||||
});
|
||||
vi.mock("openclaw/plugin-sdk/command-auth-native", async () => {
|
||||
@@ -499,13 +496,6 @@ describe("registerTelegramNativeCommands — session metadata", () => {
|
||||
},
|
||||
};
|
||||
});
|
||||
sessionMocks.resolveSessionTranscriptPath
|
||||
.mockClear()
|
||||
.mockImplementation((sessionId: string, _agentId?: string, threadId?: string | number) =>
|
||||
threadId === undefined
|
||||
? `/tmp/openclaw-sessions/${sessionId}.jsonl`
|
||||
: `/tmp/openclaw-sessions/${sessionId}-topic-${threadId}.jsonl`,
|
||||
);
|
||||
pluginRuntimeMocks.executePluginCommand.mockClear().mockResolvedValue({ text: "ok" });
|
||||
pluginRuntimeMocks.matchPluginCommand.mockClear().mockReturnValue(null);
|
||||
replyMocks.dispatchReplyWithBufferedBlockDispatcher
|
||||
@@ -1211,14 +1201,14 @@ describe("registerTelegramNativeCommands — session metadata", () => {
|
||||
expect.objectContaining({
|
||||
sessionId: "sess-topic",
|
||||
sessionKey: "agent:main:telegram:group:-1001234567890:topic:42",
|
||||
fallbackSessionFile: path.resolve("/tmp/openclaw-sessions", "sess-topic-topic-42.jsonl"),
|
||||
fallbackSessionFile: "sqlite-transcript://main/sess-topic.jsonl",
|
||||
}),
|
||||
);
|
||||
expect(pluginRuntimeMocks.executePluginCommand).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
sessionKey: "agent:main:telegram:group:-1001234567890:topic:42",
|
||||
sessionId: "sess-topic",
|
||||
sessionFile: path.resolve("/tmp/openclaw-sessions", "sess-topic-topic-42.jsonl"),
|
||||
sessionFile: "sqlite-transcript://main/sess-topic.jsonl",
|
||||
messageThreadId: 42,
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -24,7 +24,7 @@ export function resolveBtwSessionTranscriptPath(params: {
|
||||
return createSqliteSessionTranscriptLocator({ agentId, sessionId: params.sessionId });
|
||||
} catch (error) {
|
||||
diag.debug(
|
||||
`resolveSessionTranscriptPath failed: sessionId=${params.sessionId} err=${String(error)}`,
|
||||
`createSqliteSessionTranscriptLocator failed: sessionId=${params.sessionId} err=${String(error)}`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -12,11 +12,7 @@ import {
|
||||
resolveSessionKey,
|
||||
updateLastRoute,
|
||||
} from "./sessions.js";
|
||||
import {
|
||||
resolveSessionFilePath,
|
||||
resolveSessionTranscriptPath,
|
||||
resolveSessionTranscriptsDir,
|
||||
} from "./sessions/paths.js";
|
||||
import { resolveSessionFilePath, resolveSessionTranscriptsDir } from "./sessions/paths.js";
|
||||
import {
|
||||
deleteSessionEntry,
|
||||
listSessionEntries,
|
||||
@@ -611,21 +607,6 @@ describe("sessions", () => {
|
||||
expect(dir).toBe(path.join(path.resolve("/custom/state"), "agents", "main", "sessions"));
|
||||
});
|
||||
|
||||
it("includes topic ids in session transcript filenames", () => {
|
||||
withStateDir("/custom/state", () => {
|
||||
const sessionFile = resolveSessionTranscriptPath("sess-1", "main", 123);
|
||||
expect(sessionFile).toBe(
|
||||
path.join(
|
||||
path.resolve("/custom/state"),
|
||||
"agents",
|
||||
"main",
|
||||
"sessions",
|
||||
"sess-1-topic-123.jsonl",
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it("uses agent id when resolving session file fallback paths", () => {
|
||||
withStateDir("/custom/state", () => {
|
||||
const sessionFile = resolveSessionFilePath("sess-2", undefined, {
|
||||
|
||||
@@ -99,33 +99,6 @@ export function isSqliteSessionTranscriptLocator(locator: string | undefined): b
|
||||
return typeof locator === "string" && parseSqliteSessionTranscriptLocator(locator) !== undefined;
|
||||
}
|
||||
|
||||
export function resolveSessionTranscriptPathInDir(
|
||||
sessionId: string,
|
||||
sessionsDir: string,
|
||||
topicId?: string | number,
|
||||
): string {
|
||||
const safeSessionId = validateSessionId(sessionId);
|
||||
const safeTopicId =
|
||||
typeof topicId === "string"
|
||||
? encodeURIComponent(topicId)
|
||||
: typeof topicId === "number"
|
||||
? String(topicId)
|
||||
: undefined;
|
||||
const fileName =
|
||||
safeTopicId !== undefined
|
||||
? `${safeSessionId}-topic-${safeTopicId}.jsonl`
|
||||
: `${safeSessionId}.jsonl`;
|
||||
return path.resolve(sessionsDir, fileName);
|
||||
}
|
||||
|
||||
export function resolveSessionTranscriptPath(
|
||||
sessionId: string,
|
||||
agentId?: string,
|
||||
topicId?: string | number,
|
||||
): string {
|
||||
return resolveSessionTranscriptPathInDir(sessionId, resolveAgentSessionsDir(agentId), topicId);
|
||||
}
|
||||
|
||||
export function resolveSessionFilePath(
|
||||
sessionId: string,
|
||||
entry?: { sessionFile?: string },
|
||||
|
||||
@@ -9,7 +9,6 @@ import { resolveSessionLifecycleTimestamps } from "./lifecycle.js";
|
||||
import {
|
||||
createSqliteSessionTranscriptLocator,
|
||||
resolveSessionFilePath,
|
||||
resolveSessionTranscriptPathInDir,
|
||||
validateSessionId,
|
||||
} from "./paths.js";
|
||||
import { evaluateSessionFreshness, resolveSessionResetPolicy } from "./reset.js";
|
||||
@@ -38,13 +37,6 @@ describe("session path safety", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("resolves transcript path inside an explicit sessions dir", () => {
|
||||
const sessionsDir = "/tmp/openclaw/agents/main/sessions";
|
||||
const resolved = resolveSessionTranscriptPathInDir("sess-1", sessionsDir, "topic/a+b");
|
||||
|
||||
expect(resolved).toBe(path.resolve(sessionsDir, "sess-1-topic-topic%2Fa%2Bb.jsonl"));
|
||||
});
|
||||
|
||||
it("ignores legacy sessionFile paths", () => {
|
||||
const resolved = resolveSessionFilePath("sess-1", {
|
||||
sessionFile: "/tmp/openclaw/agents/work/not-sessions/abc-123.jsonl",
|
||||
@@ -574,7 +566,7 @@ describe("resolveAndPersistSessionFile", () => {
|
||||
it("creates and persists a SQLite locator when session is not yet present", async () => {
|
||||
const sessionId = "new-session-id";
|
||||
const sessionKey = "agent:main:telegram:group:123";
|
||||
const fallbackSessionFile = resolveSessionTranscriptPathInDir(sessionId, fixture.sessionsDir());
|
||||
const fallbackSessionFile = path.join(fixture.sessionsDir(), `${sessionId}.jsonl`);
|
||||
const expectedSessionFile = createSqliteSessionTranscriptLocator({
|
||||
agentId: "main",
|
||||
sessionId,
|
||||
@@ -596,7 +588,7 @@ describe("resolveAndPersistSessionFile", () => {
|
||||
it("normalizes legacy stored transcript paths to SQLite locators", async () => {
|
||||
const sessionId = "legacy-path-session-id";
|
||||
const sessionKey = "agent:main:telegram:group:456";
|
||||
const legacySessionFile = resolveSessionTranscriptPathInDir(sessionId, fixture.sessionsDir());
|
||||
const legacySessionFile = path.join(fixture.sessionsDir(), `${sessionId}.jsonl`);
|
||||
const expectedSessionFile = createSqliteSessionTranscriptLocator({
|
||||
agentId: "main",
|
||||
sessionId,
|
||||
@@ -626,10 +618,7 @@ describe("resolveAndPersistSessionFile", () => {
|
||||
const previousSessionId = "old-session-id";
|
||||
const nextSessionId = "new-session-id";
|
||||
const sessionKey = "agent:main:telegram:group:123";
|
||||
const previousSessionFile = resolveSessionTranscriptPathInDir(
|
||||
previousSessionId,
|
||||
fixture.sessionsDir(),
|
||||
);
|
||||
const previousSessionFile = path.join(fixture.sessionsDir(), `${previousSessionId}.jsonl`);
|
||||
const expectedNextSessionFile = createSqliteSessionTranscriptLocator({
|
||||
agentId: "main",
|
||||
sessionId: nextSessionId,
|
||||
|
||||
@@ -8,10 +8,7 @@ import {
|
||||
closeOpenClawStateDatabaseForTest,
|
||||
openOpenClawStateDatabase,
|
||||
} from "../../state/openclaw-state-db.js";
|
||||
import {
|
||||
createSqliteSessionTranscriptLocator,
|
||||
resolveSessionTranscriptPathInDir,
|
||||
} from "./paths.js";
|
||||
import { createSqliteSessionTranscriptLocator } from "./paths.js";
|
||||
import { upsertSessionEntry } from "./store.js";
|
||||
import { useTempSessionsFixture } from "./test-helpers.js";
|
||||
import { appendSessionTranscriptMessage } from "./transcript-append.js";
|
||||
@@ -431,7 +428,10 @@ describe("appendAssistantMessageToSessionTranscript", () => {
|
||||
|
||||
it("serializes concurrent parent-linked transcript appends", async () => {
|
||||
const targetSessionId = "concurrent-tree-session";
|
||||
const sessionFile = resolveSessionTranscriptPathInDir(targetSessionId, fixture.sessionsDir());
|
||||
const sessionFile = createSqliteSessionTranscriptLocator({
|
||||
agentId: "main",
|
||||
sessionId: targetSessionId,
|
||||
});
|
||||
appendSqliteSessionTranscriptEvent({
|
||||
agentId: "main",
|
||||
sessionId: targetSessionId,
|
||||
@@ -470,7 +470,10 @@ describe("appendAssistantMessageToSessionTranscript", () => {
|
||||
|
||||
it("appends to existing SQLite transcript chains", async () => {
|
||||
const targetSessionId = "small-linear-session";
|
||||
const sessionFile = resolveSessionTranscriptPathInDir(targetSessionId, fixture.sessionsDir());
|
||||
const sessionFile = createSqliteSessionTranscriptLocator({
|
||||
agentId: "main",
|
||||
sessionId: targetSessionId,
|
||||
});
|
||||
appendSqliteSessionTranscriptEvent({
|
||||
agentId: "main",
|
||||
sessionId: targetSessionId,
|
||||
@@ -525,10 +528,10 @@ describe("appendAssistantMessageToSessionTranscript", () => {
|
||||
it("appends scoped SQLite transcript entries without importing JSONL at runtime", async () => {
|
||||
const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-transcript-state-"));
|
||||
vi.stubEnv("OPENCLAW_STATE_DIR", stateDir);
|
||||
const sessionFile = resolveSessionTranscriptPathInDir(
|
||||
"sqlite-import-session",
|
||||
fixture.sessionsDir(),
|
||||
);
|
||||
const sessionFile = createSqliteSessionTranscriptLocator({
|
||||
agentId: "main",
|
||||
sessionId: "sqlite-import-session",
|
||||
});
|
||||
appendSqliteSessionTranscriptEvent({
|
||||
agentId: "main",
|
||||
sessionId: "sqlite-import-session",
|
||||
@@ -572,10 +575,10 @@ describe("appendAssistantMessageToSessionTranscript", () => {
|
||||
it("mirrors a newly created scoped transcript header into SQLite", async () => {
|
||||
const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-transcript-state-"));
|
||||
vi.stubEnv("OPENCLAW_STATE_DIR", stateDir);
|
||||
const sessionFile = resolveSessionTranscriptPathInDir(
|
||||
"sqlite-new-session",
|
||||
fixture.sessionsDir(),
|
||||
);
|
||||
const sessionFile = createSqliteSessionTranscriptLocator({
|
||||
agentId: "main",
|
||||
sessionId: "sqlite-new-session",
|
||||
});
|
||||
|
||||
const appended = await appendSessionTranscriptMessage({
|
||||
transcriptPath: sessionFile,
|
||||
|
||||
@@ -84,7 +84,7 @@ const normalizeVerboseLevelMock = createMock();
|
||||
export const isThinkingLevelSupportedMock = createMock();
|
||||
export const resolveSupportedThinkingLevelMock = createMock();
|
||||
const supportsXHighThinkingMock = createMock();
|
||||
const resolveSessionTranscriptPathMock = createMock();
|
||||
const createSqliteSessionTranscriptLocatorMock = createMock();
|
||||
const setSessionRuntimeModelMock = createMock();
|
||||
const registerAgentRunContextMock = createMock();
|
||||
const buildSafeExternalPromptMock = createMock();
|
||||
@@ -117,7 +117,7 @@ vi.mock("./run.runtime.js", () => ({
|
||||
isThinkingLevelSupported: isThinkingLevelSupportedMock,
|
||||
resolveSupportedThinkingLevel: resolveSupportedThinkingLevelMock,
|
||||
supportsXHighThinking: supportsXHighThinkingMock,
|
||||
resolveSessionTranscriptPath: resolveSessionTranscriptPathMock,
|
||||
createSqliteSessionTranscriptLocator: createSqliteSessionTranscriptLocatorMock,
|
||||
setSessionRuntimeModel: setSessionRuntimeModelMock,
|
||||
setCliSessionId: vi.fn(),
|
||||
logWarn: (...args: unknown[]) => logWarnMock(...args),
|
||||
@@ -174,7 +174,6 @@ vi.mock("./run-execution.runtime.js", () => ({
|
||||
countActiveDescendantRuns: countActiveDescendantRunsMock,
|
||||
listDescendantRunsForRequester: listDescendantRunsForRequesterMock,
|
||||
normalizeVerboseLevel: normalizeVerboseLevelMock,
|
||||
resolveSessionTranscriptPath: resolveSessionTranscriptPathMock,
|
||||
registerAgentRunContext: registerAgentRunContextMock,
|
||||
logWarn: (...args: unknown[]) => logWarnMock(...args),
|
||||
}));
|
||||
@@ -357,7 +356,10 @@ function resetRunExecutionMocks(): void {
|
||||
resolveFastModeStateMock.mockImplementation((params) => resolveFastModeStateImpl(params));
|
||||
resolveCronAgentLaneMock.mockReturnValue(undefined);
|
||||
normalizeVerboseLevelMock.mockImplementation((value: unknown) => value ?? "off");
|
||||
resolveSessionTranscriptPathMock.mockReturnValue("/tmp/transcript.jsonl");
|
||||
createSqliteSessionTranscriptLocatorMock.mockImplementation(
|
||||
({ agentId = "main", sessionId }: { agentId?: string; sessionId: string }) =>
|
||||
`sqlite-transcript://${agentId}/${sessionId}.jsonl`,
|
||||
);
|
||||
registerAgentRunContextMock.mockReturnValue(undefined);
|
||||
runWithModelFallbackMock.mockReset();
|
||||
runWithModelFallbackMock.mockResolvedValue(makeDefaultModelFallbackResult());
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, type Mock } from "vitest";
|
||||
import { resolveSessionTranscriptPath } from "../config/sessions/paths.js";
|
||||
import { createSqliteSessionTranscriptLocator } from "../config/sessions/paths.js";
|
||||
import { replaceSqliteSessionTranscriptEvents } from "../config/sessions/transcript-store.sqlite.js";
|
||||
import { emitAgentEvent } from "../infra/agent-events.js";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
@@ -51,7 +51,7 @@ async function emitLifecycleAssistantReply(params: {
|
||||
};
|
||||
const sessionId = commandParams.sessionId ?? params.defaultSessionId;
|
||||
const runId = commandParams.runId ?? sessionId;
|
||||
const sessionFile = resolveSessionTranscriptPath(sessionId);
|
||||
const sessionFile = createSqliteSessionTranscriptLocator({ agentId: "main", sessionId });
|
||||
|
||||
const startedAt = Date.now();
|
||||
emitAgentEvent({
|
||||
|
||||
Reference in New Issue
Block a user