mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-22 14:17:14 +00:00
refactor: simplify session store loads
This commit is contained in:
@@ -546,7 +546,7 @@ function resolveCanonicalSessionKeyFromSessionId(params: {
|
||||
agentId: params.agentId,
|
||||
},
|
||||
);
|
||||
const store = params.api.runtime.agent.session.loadSessionStore(storePath, { clone: false });
|
||||
const store = params.api.runtime.agent.session.loadSessionStore(storePath);
|
||||
let bestMatch:
|
||||
| {
|
||||
sessionKey: string;
|
||||
@@ -673,7 +673,7 @@ function resolveRecallRunChannelContext(params: {
|
||||
agentId: params.agentId,
|
||||
},
|
||||
);
|
||||
const store = params.api.runtime.agent.session.loadSessionStore(storePath, { clone: false });
|
||||
const store = params.api.runtime.agent.session.loadSessionStore(storePath);
|
||||
const sessionEntry = resolveSessionStoreEntry({
|
||||
store,
|
||||
sessionKey: resolvedSessionKey,
|
||||
@@ -1554,7 +1554,7 @@ async function persistPluginStatusLines(params: {
|
||||
agentId ? { agentId } : undefined,
|
||||
);
|
||||
if (!params.statusLine && !debugLine) {
|
||||
const store = params.api.runtime.agent.session.loadSessionStore(storePath, { clone: false });
|
||||
const store = params.api.runtime.agent.session.loadSessionStore(storePath);
|
||||
const existingEntry = resolveSessionStoreEntry({ store, sessionKey }).existing;
|
||||
const hasActiveMemoryEntry = Array.isArray(existingEntry?.pluginDebugEntries)
|
||||
? existingEntry.pluginDebugEntries.some((entry) => entry?.pluginId === "active-memory")
|
||||
|
||||
@@ -241,7 +241,7 @@ export function resolveDiscordModelPickerCurrentModel(params: {
|
||||
const storePath = resolveStorePath(params.cfg.session?.store, {
|
||||
agentId: params.route.agentId,
|
||||
});
|
||||
const sessionStore = loadSessionStore(storePath, { skipCache: true });
|
||||
const sessionStore = loadSessionStore(storePath);
|
||||
const sessionEntry = sessionStore[params.route.sessionKey];
|
||||
const override = resolveStoredModelOverride({
|
||||
sessionEntry,
|
||||
@@ -270,7 +270,7 @@ export function resolveDiscordModelPickerCurrentRuntime(params: {
|
||||
const storePath = resolveStorePath(params.cfg.session?.store, {
|
||||
agentId: params.route.agentId,
|
||||
});
|
||||
const sessionStore = loadSessionStore(storePath, { skipCache: true });
|
||||
const sessionStore = loadSessionStore(storePath);
|
||||
const sessionRuntime = normalizeOptionalString(
|
||||
sessionStore[params.route.sessionKey]?.agentRuntimeOverride,
|
||||
);
|
||||
|
||||
@@ -672,7 +672,7 @@ describe("Discord model picker interactions", () => {
|
||||
mi: "1",
|
||||
});
|
||||
|
||||
const store = loadSessionStore(storePath, { skipCache: true });
|
||||
const store = loadSessionStore(storePath);
|
||||
expect(store["agent:worker:subagent:bound"]?.providerOverride).toBe("lmstudio");
|
||||
expect(store["agent:worker:subagent:bound"]?.modelOverride).toBe(
|
||||
"unsloth/gemma-4-26b-a4b-it@iq4_xs",
|
||||
@@ -723,7 +723,7 @@ describe("Discord model picker interactions", () => {
|
||||
createModelsViewSubmitData(),
|
||||
);
|
||||
|
||||
const store = loadSessionStore(storePath, { skipCache: true });
|
||||
const store = loadSessionStore(storePath);
|
||||
expect(store["agent:worker:subagent:bound"]?.providerOverride).toBeUndefined();
|
||||
expect(store["agent:worker:subagent:bound"]?.modelOverride).toBeUndefined();
|
||||
expect(JSON.stringify(submitInteraction.followUp.mock.calls[0]?.[0])).toContain(
|
||||
|
||||
@@ -15,7 +15,7 @@ export function resolveFeishuReasoningPreviewEnabled(params: {
|
||||
}
|
||||
|
||||
try {
|
||||
const store = loadSessionStore(params.storePath, { skipCache: true });
|
||||
const store = loadSessionStore(params.storePath);
|
||||
const level = resolveSessionStoreEntry({ store, sessionKey: params.sessionKey }).existing
|
||||
?.reasoningLevel;
|
||||
if (level === "on" || level === "stream" || level === "off") {
|
||||
|
||||
@@ -244,7 +244,7 @@ export function resolveMattermostModelPickerCurrentModel(params: {
|
||||
agentId: params.route.agentId,
|
||||
});
|
||||
const sessionStore = params.skipCache
|
||||
? loadSessionStore(storePath, { skipCache: true })
|
||||
? loadSessionStore(storePath)
|
||||
: loadSessionStore(storePath);
|
||||
const sessionEntry = sessionStore[params.route.sessionKey];
|
||||
const override = resolveStoredModelOverride({
|
||||
|
||||
@@ -1199,7 +1199,6 @@ export async function monitorMattermostProvider(opts: MonitorMattermostOpts = {}
|
||||
cfg,
|
||||
route: modelSessionRoute,
|
||||
data,
|
||||
skipCache: true,
|
||||
});
|
||||
const view = renderMattermostModelsPickerView({
|
||||
ownerUserId: pickerState.ownerUserId,
|
||||
|
||||
@@ -119,7 +119,7 @@ describe("Telegram direct session recreation after delete", () => {
|
||||
onRecordError: context.turn.record.onRecordError,
|
||||
});
|
||||
|
||||
const store = loadSessionStore(storePath, { skipCache: true });
|
||||
const store = loadSessionStore(storePath);
|
||||
expect(context?.ctxPayload?.SessionKey).toBe(TELEGRAM_DIRECT_KEY);
|
||||
expect(store[TELEGRAM_DIRECT_KEY]).toEqual(
|
||||
expect.objectContaining({
|
||||
|
||||
@@ -221,9 +221,7 @@ function resolveTelegramReasoningLevel(params: {
|
||||
}
|
||||
try {
|
||||
const storePath = telegramDeps.resolveStorePath(cfg.session?.store, { agentId });
|
||||
const store = (telegramDeps.loadSessionStore ?? loadSessionStore)(storePath, {
|
||||
skipCache: true,
|
||||
});
|
||||
const store = (telegramDeps.loadSessionStore ?? loadSessionStore)(storePath);
|
||||
const entry = resolveSessionStoreEntry({ store, sessionKey }).existing;
|
||||
const level = entry?.reasoningLevel;
|
||||
if (level === "on" || level === "stream" || level === "off") {
|
||||
@@ -950,9 +948,7 @@ export const dispatchTelegramMessage = async ({
|
||||
const storePath = telegramDeps.resolveStorePath(cfg.session?.store, {
|
||||
agentId: route.agentId,
|
||||
});
|
||||
const store = (telegramDeps.loadSessionStore ?? loadSessionStore)(storePath, {
|
||||
skipCache: true,
|
||||
});
|
||||
const store = (telegramDeps.loadSessionStore ?? loadSessionStore)(storePath);
|
||||
const sessionKey = ctxPayload.SessionKey;
|
||||
if (sessionKey) {
|
||||
const entry = resolveSessionStoreEntry({ store, sessionKey }).existing;
|
||||
|
||||
@@ -55,9 +55,7 @@ const { getRuntimeConfig, loadSessionStoreMock, resolveStorePathMock, sessionSto
|
||||
sessionStoreEntries: { value: SessionStore };
|
||||
} => ({
|
||||
getRuntimeConfig: vi.fn<GetRuntimeConfigFn>(() => ({})),
|
||||
loadSessionStoreMock: vi.fn<LoadSessionStoreFn>(
|
||||
(_storePath, _opts) => sessionStoreEntries.value,
|
||||
),
|
||||
loadSessionStoreMock: vi.fn<LoadSessionStoreFn>(() => sessionStoreEntries.value),
|
||||
resolveStorePathMock: vi.fn<ResolveStorePathFn>(
|
||||
(storePath?: string) => storePath ?? sessionStorePath,
|
||||
),
|
||||
|
||||
@@ -226,7 +226,7 @@ describe("createTelegramBot", () => {
|
||||
|
||||
expect(replySpy).not.toHaveBeenCalled();
|
||||
expect(editMessageTextSpy).not.toHaveBeenCalled();
|
||||
expect(loadSessionStore(storePath, { skipCache: true })).toEqual({});
|
||||
expect(loadSessionStore(storePath)).toEqual({});
|
||||
expect(answerCallbackQuerySpy).toHaveBeenCalledWith("cbq-model-authz-bypass-1");
|
||||
} finally {
|
||||
await rm(storePath, { force: true });
|
||||
@@ -299,7 +299,7 @@ describe("createTelegramBot", () => {
|
||||
|
||||
expect(replySpy).not.toHaveBeenCalled();
|
||||
expect(editMessageTextSpy).not.toHaveBeenCalled();
|
||||
expect(loadSessionStore(storePath, { skipCache: true })).toEqual({});
|
||||
expect(loadSessionStore(storePath)).toEqual({});
|
||||
expect(answerCallbackQuerySpy).toHaveBeenCalledWith("cbq-group-model-authz-1");
|
||||
} finally {
|
||||
await rm(storePath, { force: true });
|
||||
@@ -381,7 +381,7 @@ describe("createTelegramBot", () => {
|
||||
|
||||
expect(replySpy).not.toHaveBeenCalled();
|
||||
expect(editMessageTextSpy).not.toHaveBeenCalled();
|
||||
expect(loadSessionStore(storePath, { skipCache: true })).toEqual({});
|
||||
expect(loadSessionStore(storePath)).toEqual({});
|
||||
expect(answerCallbackQuerySpy).toHaveBeenCalledWith("cbq-group-model-authz-runtime-1");
|
||||
} finally {
|
||||
loadConfig.mockReset();
|
||||
@@ -1104,7 +1104,7 @@ describe("createTelegramBot", () => {
|
||||
"Session selection cleared. Runtime unchanged. New replies use the agent's configured default.",
|
||||
);
|
||||
|
||||
const entry = Object.values(loadSessionStore(storePath, { skipCache: true }))[0];
|
||||
const entry = Object.values(loadSessionStore(storePath))[0];
|
||||
expect(entry?.providerOverride).toBeUndefined();
|
||||
expect(entry?.modelOverride).toBeUndefined();
|
||||
expect(answerCallbackQuerySpy).toHaveBeenCalledWith("cbq-model-compact-1");
|
||||
@@ -1255,7 +1255,7 @@ describe("createTelegramBot", () => {
|
||||
"Session selection cleared. Runtime unchanged. New replies use the agent's configured default.",
|
||||
);
|
||||
|
||||
const entry = Object.values(loadSessionStore(storePath, { skipCache: true }))[0];
|
||||
const entry = Object.values(loadSessionStore(storePath))[0];
|
||||
expect(entry?.providerOverride).toBeUndefined();
|
||||
expect(entry?.modelOverride).toBeUndefined();
|
||||
expect(answerCallbackQuerySpy).toHaveBeenCalledWith("cbq-model-default-1");
|
||||
@@ -1330,7 +1330,7 @@ describe("createTelegramBot", () => {
|
||||
expect.objectContaining({ parse_mode: "HTML" }),
|
||||
);
|
||||
|
||||
const entry = Object.values(loadSessionStore(storePath, { skipCache: true }))[0];
|
||||
const entry = Object.values(loadSessionStore(storePath))[0];
|
||||
expect(entry?.providerOverride).toBe("openai");
|
||||
expect(entry?.modelOverride).toBe("gpt-5.4");
|
||||
expect(answerCallbackQuerySpy).toHaveBeenCalledWith("cbq-model-html-1");
|
||||
@@ -1420,7 +1420,7 @@ describe("createTelegramBot", () => {
|
||||
|
||||
// Override must be persisted (not cleared) because openai/gpt-5.4 is
|
||||
// NOT the default in the fresh config.
|
||||
const entry = Object.values(loadSessionStore(storePath, { skipCache: true }))[0];
|
||||
const entry = Object.values(loadSessionStore(storePath))[0];
|
||||
expect(entry?.providerOverride).toBe("openai");
|
||||
expect(entry?.modelOverride).toBe("gpt-5.4");
|
||||
} finally {
|
||||
|
||||
@@ -52,7 +52,7 @@ const expectWorkGroupActivationEntry = async (
|
||||
assertEntry?: (entry: SessionStoreEntry | undefined) => void,
|
||||
) => {
|
||||
await vi.waitFor(() => {
|
||||
const scopedEntry = loadSessionStore(storePath, { skipCache: true })[WORK_GROUP_SESSION_KEY];
|
||||
const scopedEntry = loadSessionStore(storePath)[WORK_GROUP_SESSION_KEY];
|
||||
expect(scopedEntry?.groupActivation).toBe("always");
|
||||
assertEntry?.(scopedEntry);
|
||||
});
|
||||
|
||||
@@ -382,7 +382,7 @@ describe("updateSessionStoreAfterAgentRun", () => {
|
||||
} as never,
|
||||
});
|
||||
|
||||
const persisted = loadSessionStore(storePath, { skipCache: true })[sessionKey];
|
||||
const persisted = loadSessionStore(storePath)[sessionKey];
|
||||
expect(persisted?.acp).toMatchObject({
|
||||
backend: "acpx",
|
||||
agent: "codex",
|
||||
@@ -438,7 +438,7 @@ describe("updateSessionStoreAfterAgentRun", () => {
|
||||
} as never,
|
||||
});
|
||||
|
||||
const persisted = loadSessionStore(storePath, { skipCache: true })[sessionKey];
|
||||
const persisted = loadSessionStore(storePath)[sessionKey];
|
||||
expect(persisted).toMatchObject({
|
||||
status: "done",
|
||||
startedAt: 1_000,
|
||||
@@ -502,7 +502,7 @@ describe("updateSessionStoreAfterAgentRun", () => {
|
||||
} as never,
|
||||
});
|
||||
|
||||
const persisted = loadSessionStore(storePath, { skipCache: true })[sessionKey];
|
||||
const persisted = loadSessionStore(storePath)[sessionKey];
|
||||
expect(persisted?.systemPromptReport?.bootstrapTruncation?.warningSignaturesSeen).toEqual([
|
||||
"sig-a",
|
||||
"sig-b",
|
||||
@@ -572,7 +572,7 @@ describe("updateSessionStoreAfterAgentRun", () => {
|
||||
authEpoch: "auth-epoch-1",
|
||||
});
|
||||
|
||||
const persisted = loadSessionStore(storePath, { skipCache: true })[first.sessionKey!];
|
||||
const persisted = loadSessionStore(storePath)[first.sessionKey!];
|
||||
expect(persisted?.cliSessionBindings?.["claude-cli"]).toEqual({
|
||||
sessionId: "claude-cli-session-1",
|
||||
authEpoch: "auth-epoch-1",
|
||||
@@ -1225,7 +1225,7 @@ describe("clearCliSessionInStore", () => {
|
||||
expect(cleared?.claudeCliSessionId).toBeUndefined();
|
||||
expect(sessionStore[sessionKey]).toEqual(cleared);
|
||||
|
||||
const persisted = loadSessionStore(storePath, { skipCache: true })[sessionKey];
|
||||
const persisted = loadSessionStore(storePath)[sessionKey];
|
||||
expect(persisted?.cliSessionBindings?.["claude-cli"]).toBeUndefined();
|
||||
expect(persisted?.cliSessionBindings?.["codex-cli"]).toEqual({
|
||||
sessionId: "codex-session-1",
|
||||
@@ -1257,9 +1257,7 @@ describe("clearCliSessionInStore", () => {
|
||||
|
||||
expect(cleared).toBeUndefined();
|
||||
expect(sessionStore[existingKey]?.claudeCliSessionId).toBe("claude-session-1");
|
||||
expect(
|
||||
loadSessionStore(storePath, { skipCache: true })[existingKey]?.claudeCliSessionId,
|
||||
).toBe("claude-session-1");
|
||||
expect(loadSessionStore(storePath)[existingKey]?.claudeCliSessionId).toBe("claude-session-1");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -662,7 +662,7 @@ describe("runReplyAgent Active Memory inline debug", () => {
|
||||
);
|
||||
|
||||
runEmbeddedPiAgentMock.mockImplementationOnce(async () => {
|
||||
const latest = loadSessionStore(storePath, { skipCache: true });
|
||||
const latest = loadSessionStore(storePath);
|
||||
latest[sessionKey] = {
|
||||
...latest[sessionKey],
|
||||
pluginDebugEntries: [
|
||||
@@ -774,7 +774,7 @@ describe("runReplyAgent Active Memory inline debug", () => {
|
||||
);
|
||||
|
||||
runEmbeddedPiAgentMock.mockImplementationOnce(async () => {
|
||||
const latest = loadSessionStore(storePath, { skipCache: true });
|
||||
const latest = loadSessionStore(storePath);
|
||||
latest[sessionKey] = {
|
||||
...latest[sessionKey],
|
||||
pluginDebugEntries: [
|
||||
@@ -885,7 +885,7 @@ describe("runReplyAgent Active Memory inline debug", () => {
|
||||
);
|
||||
|
||||
runEmbeddedPiAgentMock.mockImplementationOnce(async () => {
|
||||
const latest = loadSessionStore(storePath, { skipCache: true });
|
||||
const latest = loadSessionStore(storePath);
|
||||
latest[sessionKey] = {
|
||||
...latest[sessionKey],
|
||||
pluginDebugEntries: [
|
||||
@@ -1612,7 +1612,7 @@ describe("runReplyAgent Active Memory inline debug", () => {
|
||||
typingMode: "instant",
|
||||
});
|
||||
|
||||
expect(loadSessionStoreSpy).not.toHaveBeenCalledWith(storePath, { skipCache: true });
|
||||
expect(loadSessionStoreSpy).not.toHaveBeenCalledWith(storePath);
|
||||
expect(result).toMatchObject({ text: "Normal reply" });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -202,9 +202,7 @@ describe("buildExportSessionReply", () => {
|
||||
});
|
||||
|
||||
expect(hoisted.resolveDefaultSessionStorePathMock).not.toHaveBeenCalled();
|
||||
expect(hoisted.loadSessionStoreMock).toHaveBeenCalledWith("/tmp/custom-store/sessions.json", {
|
||||
skipCache: true,
|
||||
});
|
||||
expect(hoisted.loadSessionStoreMock).toHaveBeenCalledWith("/tmp/custom-store/sessions.json");
|
||||
expect(hoisted.resolveSessionFilePathOptionsMock).toHaveBeenCalledWith({
|
||||
agentId: "target",
|
||||
storePath: "/tmp/custom-store/sessions.json",
|
||||
|
||||
@@ -218,7 +218,7 @@ async function persistRunSessionUsageForFollowupTest(
|
||||
return;
|
||||
}
|
||||
const registeredStore = FOLLOWUP_TEST_SESSION_STORES.get(storePath);
|
||||
const store = registeredStore ?? loadSessionStore(storePath, { skipCache: true });
|
||||
const store = registeredStore ?? loadSessionStore(storePath);
|
||||
const entry = store[sessionKey];
|
||||
if (!entry) {
|
||||
return;
|
||||
@@ -962,7 +962,7 @@ describe("createFollowupRunner compaction", () => {
|
||||
if (registeredStore) {
|
||||
registeredStore[params.sessionKey] = updatedEntry;
|
||||
} else {
|
||||
const store = loadSessionStore(params.storePath, { skipCache: true });
|
||||
const store = loadSessionStore(params.storePath);
|
||||
store[params.sessionKey] = updatedEntry;
|
||||
await saveSessionStore(params.storePath, store);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ function expectSessionStore(
|
||||
storePath: string,
|
||||
sessions: Record<string, { sessionId: string; updatedAt: number }>,
|
||||
) {
|
||||
expect(loadSessionStore(storePath, { skipCache: true })).toEqual(sessions);
|
||||
expect(loadSessionStore(storePath)).toEqual(sessions);
|
||||
}
|
||||
|
||||
function readJsonLogs(): Array<Record<string, unknown>> {
|
||||
|
||||
@@ -879,7 +879,7 @@ describe("sessions", () => {
|
||||
parseSpy.mockRestore();
|
||||
}
|
||||
|
||||
const store = loadSessionStore(storePath, { skipCache: true });
|
||||
const store = loadSessionStore(storePath);
|
||||
expect(store[mainSessionKey]?.thinkingLevel).toBe("high");
|
||||
});
|
||||
|
||||
|
||||
@@ -529,7 +529,7 @@ describe("resolveAndPersistSessionFile", () => {
|
||||
},
|
||||
};
|
||||
fs.writeFileSync(fixture.storePath(), JSON.stringify(store), "utf-8");
|
||||
const sessionStore = loadSessionStore(fixture.storePath(), { skipCache: true });
|
||||
const sessionStore = loadSessionStore(fixture.storePath());
|
||||
const fallbackSessionFile = resolveSessionTranscriptPathInDir(
|
||||
sessionId,
|
||||
fixture.sessionsDir(),
|
||||
@@ -547,7 +547,7 @@ describe("resolveAndPersistSessionFile", () => {
|
||||
|
||||
expect(result.sessionFile).toBe(fallbackSessionFile);
|
||||
|
||||
const saved = loadSessionStore(fixture.storePath(), { skipCache: true });
|
||||
const saved = loadSessionStore(fixture.storePath());
|
||||
expect(saved[sessionKey]?.sessionFile).toBe(fallbackSessionFile);
|
||||
});
|
||||
|
||||
@@ -555,7 +555,7 @@ describe("resolveAndPersistSessionFile", () => {
|
||||
const sessionId = "new-session-id";
|
||||
const sessionKey = "agent:main:telegram:group:123";
|
||||
fs.writeFileSync(fixture.storePath(), JSON.stringify({}), "utf-8");
|
||||
const sessionStore = loadSessionStore(fixture.storePath(), { skipCache: true });
|
||||
const sessionStore = loadSessionStore(fixture.storePath());
|
||||
const fallbackSessionFile = resolveSessionTranscriptPathInDir(sessionId, fixture.sessionsDir());
|
||||
|
||||
const result = await resolveAndPersistSessionFile({
|
||||
@@ -568,7 +568,7 @@ describe("resolveAndPersistSessionFile", () => {
|
||||
|
||||
expect(result.sessionFile).toBe(fallbackSessionFile);
|
||||
expect(result.sessionEntry.sessionId).toBe(sessionId);
|
||||
const saved = loadSessionStore(fixture.storePath(), { skipCache: true });
|
||||
const saved = loadSessionStore(fixture.storePath());
|
||||
expect(saved[sessionKey]?.sessionFile).toBe(fallbackSessionFile);
|
||||
});
|
||||
|
||||
@@ -592,7 +592,7 @@ describe("resolveAndPersistSessionFile", () => {
|
||||
},
|
||||
};
|
||||
fs.writeFileSync(fixture.storePath(), JSON.stringify(store), "utf-8");
|
||||
const sessionStore = loadSessionStore(fixture.storePath(), { skipCache: true });
|
||||
const sessionStore = loadSessionStore(fixture.storePath());
|
||||
|
||||
const result = await resolveAndPersistSessionFile({
|
||||
sessionId: nextSessionId,
|
||||
@@ -607,7 +607,7 @@ describe("resolveAndPersistSessionFile", () => {
|
||||
expect(result.sessionFile).not.toBe(previousSessionFile);
|
||||
expect(result.sessionEntry.sessionFile).toBe(expectedNextSessionFile);
|
||||
|
||||
const saved = loadSessionStore(fixture.storePath(), { skipCache: true });
|
||||
const saved = loadSessionStore(fixture.storePath());
|
||||
expect(saved[sessionKey]?.sessionFile).toBe(expectedNextSessionFile);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,7 +123,7 @@ describe("SQLite session store backend", () => {
|
||||
});
|
||||
|
||||
expect(fs.existsSync(storePath)).toBe(false);
|
||||
expect(loadSessionStore(storePath, { skipCache: true })).toEqual({
|
||||
expect(loadSessionStore(storePath)).toEqual({
|
||||
"discord:ops": {
|
||||
...entry,
|
||||
updatedAt: 200,
|
||||
@@ -145,7 +145,7 @@ describe("SQLite session store backend", () => {
|
||||
await saveSessionStore(storePath, { "discord:ops": entry });
|
||||
|
||||
expect(fs.existsSync(storePath)).toBe(false);
|
||||
expect(loadSessionStore(storePath, { skipCache: true })).toEqual({
|
||||
expect(loadSessionStore(storePath)).toEqual({
|
||||
"discord:ops": entry,
|
||||
});
|
||||
});
|
||||
@@ -170,7 +170,7 @@ describe("SQLite session store backend", () => {
|
||||
),
|
||||
);
|
||||
|
||||
expect(loadSessionStore(storePath, { skipCache: true })).toEqual({});
|
||||
expect(loadSessionStore(storePath)).toEqual({});
|
||||
|
||||
await saveSessionStore(storePath, {
|
||||
"discord:ops": {
|
||||
@@ -179,7 +179,7 @@ describe("SQLite session store backend", () => {
|
||||
updatedAt: 200,
|
||||
},
|
||||
});
|
||||
expect(loadSessionStore(storePath, { skipCache: true })).toEqual({
|
||||
expect(loadSessionStore(storePath)).toEqual({
|
||||
"discord:ops": {
|
||||
...legacyEntry,
|
||||
sessionId: "sqlite-session",
|
||||
|
||||
@@ -9,19 +9,11 @@ import type { SessionEntry } from "./types.js";
|
||||
|
||||
export { normalizeSessionStore } from "./store-normalize.js";
|
||||
|
||||
export type LoadSessionStoreOptions = {
|
||||
skipCache?: boolean;
|
||||
clone?: boolean;
|
||||
};
|
||||
|
||||
function isSessionStoreRecord(value: unknown): value is Record<string, SessionEntry> {
|
||||
return !!value && typeof value === "object" && !Array.isArray(value);
|
||||
}
|
||||
|
||||
export function loadSessionStore(
|
||||
storePath: string,
|
||||
_opts: LoadSessionStoreOptions = {},
|
||||
): Record<string, SessionEntry> {
|
||||
export function loadSessionStore(storePath: string): Record<string, SessionEntry> {
|
||||
const sqliteOptions = resolveSqliteSessionStoreOptionsForPath(storePath);
|
||||
if (sqliteOptions) {
|
||||
return loadSqliteSessionStore(sqliteOptions);
|
||||
|
||||
@@ -57,7 +57,7 @@ describe("session store key normalization", () => {
|
||||
ctx: createInboundContext(),
|
||||
});
|
||||
|
||||
const store = loadSessionStore(storePath, { skipCache: true });
|
||||
const store = loadSessionStore(storePath);
|
||||
expect(Object.keys(store)).toEqual([CANONICAL_KEY]);
|
||||
expect(store[CANONICAL_KEY]?.origin?.provider).toBe("webchat");
|
||||
});
|
||||
@@ -76,7 +76,7 @@ describe("session store key normalization", () => {
|
||||
to: "webchat:user-1",
|
||||
});
|
||||
|
||||
const store = loadSessionStore(storePath, { skipCache: true });
|
||||
const store = loadSessionStore(storePath);
|
||||
expect(Object.keys(store)).toEqual([CANONICAL_KEY]);
|
||||
expect(store[CANONICAL_KEY]).toEqual(
|
||||
expect.objectContaining({
|
||||
@@ -112,7 +112,7 @@ describe("session store key normalization", () => {
|
||||
to: "webchat:user-2",
|
||||
});
|
||||
|
||||
const store = loadSessionStore(storePath, { skipCache: true });
|
||||
const store = loadSessionStore(storePath);
|
||||
expect(store[CANONICAL_KEY]?.sessionId).toBe("legacy-session");
|
||||
expect(store[MIXED_CASE_KEY]).toBeUndefined();
|
||||
});
|
||||
@@ -149,7 +149,7 @@ describe("session store key normalization", () => {
|
||||
ctx: createInboundContext(),
|
||||
});
|
||||
|
||||
const store = loadSessionStore(storePath, { skipCache: true });
|
||||
const store = loadSessionStore(storePath);
|
||||
expect(store[CANONICAL_KEY]?.sessionId).toBe("existing-session");
|
||||
expect(store[CANONICAL_KEY]?.updatedAt).toBe(existingUpdatedAt);
|
||||
expect(store[CANONICAL_KEY]?.origin?.provider).toBe("webchat");
|
||||
|
||||
@@ -100,7 +100,7 @@ describe("session store strips resolvedSkills from persistence", () => {
|
||||
};
|
||||
|
||||
await saveSessionStore(storePath, store);
|
||||
const loaded = loadSessionStore(storePath, { skipCache: true });
|
||||
const loaded = loadSessionStore(storePath);
|
||||
|
||||
const persistedSnapshot = loaded["agent:main:test:1"]?.skillsSnapshot;
|
||||
expect(persistedSnapshot).toMatchObject({
|
||||
@@ -122,7 +122,7 @@ describe("session store strips resolvedSkills from persistence", () => {
|
||||
expect(rawLegacy).toContain("resolvedSkills");
|
||||
await fs.writeFile(storePath, rawLegacy, "utf-8");
|
||||
|
||||
const loaded = loadSessionStore(storePath, { skipCache: true });
|
||||
const loaded = loadSessionStore(storePath);
|
||||
expect(loaded["agent:main:test:1"]?.skillsSnapshot?.resolvedSkills).toBeUndefined();
|
||||
expect(loaded["agent:main:test:1"]?.skillsSnapshot?.prompt).toBe(
|
||||
legacy["agent:main:test:1"].skillsSnapshot?.prompt,
|
||||
@@ -143,7 +143,7 @@ describe("session store strips resolvedSkills from persistence", () => {
|
||||
|
||||
const raw = await fs.readFile(storePath, "utf-8");
|
||||
expect(raw).not.toContain("resolvedSkills");
|
||||
const reloaded = loadSessionStore(storePath, { skipCache: true });
|
||||
const reloaded = loadSessionStore(storePath);
|
||||
expect(reloaded["agent:main:test:1"]?.skillsSnapshot?.resolvedSkills).toBeUndefined();
|
||||
expect(reloaded["agent:main:test:1"]?.skillsSnapshot?.skills).toHaveLength(6);
|
||||
});
|
||||
|
||||
@@ -82,7 +82,7 @@ describe("runBootOnce", () => {
|
||||
|
||||
const mockAgentUpdatesMainSession = (storePath: string, sessionKey: string) => {
|
||||
agentCommand.mockImplementation(async (opts: { sessionId?: string }) => {
|
||||
const current = loadSessionStore(storePath, { skipCache: true });
|
||||
const current = loadSessionStore(storePath);
|
||||
current[sessionKey] = {
|
||||
sessionId: String(opts.sessionId),
|
||||
updatedAt: Date.now(),
|
||||
@@ -96,7 +96,7 @@ describe("runBootOnce", () => {
|
||||
sessionKey: string;
|
||||
expectedSessionId?: string;
|
||||
}) => {
|
||||
const restored = loadSessionStore(params.storePath, { skipCache: true });
|
||||
const restored = loadSessionStore(params.storePath);
|
||||
if (params.expectedSessionId === undefined) {
|
||||
expect(restored[params.sessionKey]).toBeUndefined();
|
||||
return;
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
resetSubagentRegistryForTests,
|
||||
} from "../agents/subagent-registry.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { loadSessionStore, type SessionEntry } from "../config/sessions.js";
|
||||
import { loadSessionStore, saveSessionStore, type SessionEntry } from "../config/sessions.js";
|
||||
import { registerAgentRunContext, resetAgentRunContextForTest } from "../infra/agent-events.js";
|
||||
import { withStateDirEnv } from "../test-helpers/state-dir-env.js";
|
||||
import { withEnv } from "../test-utils/env.js";
|
||||
@@ -1252,21 +1252,12 @@ describe("loadCombinedSessionStoreForGateway includes disk-only agents (#32804)"
|
||||
fs.mkdirSync(mainDir, { recursive: true });
|
||||
fs.mkdirSync(codexDir, { recursive: true });
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(mainDir, "sessions.json"),
|
||||
JSON.stringify({
|
||||
"agent:main:main": { sessionId: "s-main", updatedAt: 100 },
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(codexDir, "sessions.json"),
|
||||
JSON.stringify({
|
||||
"agent:codex:acp-task": { sessionId: "s-codex", updatedAt: 200 },
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
await saveSessionStore(path.join(mainDir, "sessions.json"), {
|
||||
"agent:main:main": { sessionId: "s-main", updatedAt: 100 },
|
||||
});
|
||||
await saveSessionStore(path.join(codexDir, "sessions.json"), {
|
||||
"agent:codex:acp-task": { sessionId: "s-codex", updatedAt: 200 },
|
||||
});
|
||||
|
||||
const cfg = {
|
||||
session: {
|
||||
@@ -1295,20 +1286,12 @@ describe("loadCombinedSessionStoreForGateway includes disk-only agents (#32804)"
|
||||
|
||||
const mainStorePath = path.join(mainDir, "sessions.json");
|
||||
const codexStorePath = path.join(codexDir, "sessions.json");
|
||||
fs.writeFileSync(
|
||||
mainStorePath,
|
||||
JSON.stringify({
|
||||
"agent:main:main": { sessionId: "s-main", updatedAt: 100 },
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
fs.writeFileSync(
|
||||
codexStorePath,
|
||||
JSON.stringify({
|
||||
"agent:codex:acp-task": { sessionId: "s-codex", updatedAt: 200 },
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
await saveSessionStore(mainStorePath, {
|
||||
"agent:main:main": { sessionId: "s-main", updatedAt: 100 },
|
||||
});
|
||||
await saveSessionStore(codexStorePath, {
|
||||
"agent:codex:acp-task": { sessionId: "s-codex", updatedAt: 200 },
|
||||
});
|
||||
|
||||
const cfg = {
|
||||
session: {
|
||||
@@ -1320,41 +1303,28 @@ describe("loadCombinedSessionStoreForGateway includes disk-only agents (#32804)"
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const readSpy = vi.spyOn(fs, "readFileSync");
|
||||
|
||||
const { store, storePath } = loadCombinedSessionStoreForGateway(cfg, { agentId: "codex" });
|
||||
|
||||
expect(storePath).toBe(fs.realpathSync.native(codexStorePath));
|
||||
expect(store["agent:codex:acp-task"]).toMatchObject({ sessionId: "s-codex" });
|
||||
expect(store["agent:main:main"]).toBeUndefined();
|
||||
const readPaths = readSpy.mock.calls
|
||||
.map((call) => call[0])
|
||||
.filter((arg): arg is string => typeof arg === "string");
|
||||
expect(readPaths).toContain(fs.realpathSync.native(codexStorePath));
|
||||
expect(readPaths).not.toContain(fs.realpathSync.native(mainStorePath));
|
||||
|
||||
readSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
test("keeps canonical single-target entries by reference", async () => {
|
||||
test("keeps canonical single-target entries intact", async () => {
|
||||
await withStateDirEnv("openclaw-acp-canonical-", async ({ stateDir }) => {
|
||||
const customRoot = path.join(stateDir, "custom-state");
|
||||
const codexDir = path.join(customRoot, "agents", "codex", "sessions");
|
||||
fs.mkdirSync(codexDir, { recursive: true });
|
||||
|
||||
const codexStorePath = path.join(codexDir, "sessions.json");
|
||||
fs.writeFileSync(
|
||||
codexStorePath,
|
||||
JSON.stringify({
|
||||
"agent:codex:acp-task": {
|
||||
sessionId: "s-codex",
|
||||
updatedAt: 200,
|
||||
spawnedBy: "agent:codex:main",
|
||||
},
|
||||
}),
|
||||
"utf8",
|
||||
);
|
||||
await saveSessionStore(codexStorePath, {
|
||||
"agent:codex:acp-task": {
|
||||
sessionId: "s-codex",
|
||||
updatedAt: 200,
|
||||
spawnedBy: "agent:codex:main",
|
||||
},
|
||||
});
|
||||
|
||||
const cfg = {
|
||||
session: {
|
||||
@@ -1366,12 +1336,12 @@ describe("loadCombinedSessionStoreForGateway includes disk-only agents (#32804)"
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const cachedStore = loadSessionStore(fs.realpathSync.native(codexStorePath), {
|
||||
clone: false,
|
||||
});
|
||||
const savedStore = loadSessionStore(
|
||||
path.join(fs.realpathSync.native(codexDir), "sessions.json"),
|
||||
);
|
||||
const { store } = loadCombinedSessionStoreForGateway(cfg, { agentId: "codex" });
|
||||
|
||||
expect(store["agent:codex:acp-task"]).toBe(cachedStore["agent:codex:acp-task"]);
|
||||
expect(store["agent:codex:acp-task"]).toEqual(savedStore["agent:codex:acp-task"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,7 +86,7 @@ describe("Telegram direct session recreation after delete", () => {
|
||||
await updateSessionStore(storePath, (store) => {
|
||||
delete store[TELEGRAM_DIRECT_KEY];
|
||||
});
|
||||
expect(loadSessionStore(storePath, { skipCache: true })[TELEGRAM_DIRECT_KEY]).toBeUndefined();
|
||||
expect(loadSessionStore(storePath)[TELEGRAM_DIRECT_KEY]).toBeUndefined();
|
||||
|
||||
const ctx = createTelegramDirectContext();
|
||||
await recordSessionMetaFromInbound({
|
||||
@@ -103,7 +103,7 @@ describe("Telegram direct session recreation after delete", () => {
|
||||
ctx,
|
||||
});
|
||||
|
||||
const store = loadSessionStore(storePath, { skipCache: true });
|
||||
const store = loadSessionStore(storePath);
|
||||
const listed = listSessionsFromStore({
|
||||
cfg,
|
||||
storePath,
|
||||
|
||||
@@ -1099,7 +1099,7 @@ describe("host-hook fixture plugin contract", () => {
|
||||
id: first.id,
|
||||
sessionKey: "agent:main:main",
|
||||
});
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
expect(
|
||||
stored["agent:main:main"]?.pluginNextTurnInjections?.["approval-fixture"],
|
||||
).toHaveLength(1);
|
||||
@@ -1205,7 +1205,7 @@ describe("host-hook fixture plugin contract", () => {
|
||||
text: "active prompt contribution",
|
||||
}),
|
||||
]);
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
expect(stored["agent:main:main"]?.pluginNextTurnInjections).toBeUndefined();
|
||||
},
|
||||
});
|
||||
@@ -2183,7 +2183,7 @@ describe("host-hook fixture plugin contract", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ failures: [] });
|
||||
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
expect(stored["agent:main:main"]).toEqual(
|
||||
expect.objectContaining({
|
||||
pluginExtensions: {
|
||||
@@ -2333,7 +2333,7 @@ describe("host-hook fixture plugin contract", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ failures: [] });
|
||||
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
expect(stored["agent:main:main"]?.pluginExtensions).toEqual({
|
||||
"restart-state-fixture": { workflow: { state: "waiting" } },
|
||||
});
|
||||
@@ -2409,7 +2409,7 @@ describe("host-hook fixture plugin contract", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ failures: [] });
|
||||
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
expect(stored["agent:main:main"]?.pluginNextTurnInjections).toBeUndefined();
|
||||
},
|
||||
});
|
||||
|
||||
@@ -711,7 +711,7 @@ describe("plugin run context lifecycle", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ failures: [] });
|
||||
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
expect(stored["agent:main:main"]?.pluginExtensions).toEqual({
|
||||
"restart-state-fixture": { workflow: { state: "waiting" } },
|
||||
});
|
||||
|
||||
@@ -78,7 +78,7 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
value: { state: "executing", title: "Deploy approval", internal: 7 },
|
||||
});
|
||||
expect(patchResult.ok).toBe(true);
|
||||
const afterPatch = loadSessionStore(storePath, { skipCache: true });
|
||||
const afterPatch = loadSessionStore(storePath);
|
||||
expect(
|
||||
(afterPatch["agent:main:main"] as unknown as Record<string, unknown>).approvalSnapshot,
|
||||
).toEqual({ state: "executing", title: "Deploy approval" });
|
||||
@@ -91,7 +91,7 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
unset: true,
|
||||
});
|
||||
expect(unsetResult.ok).toBe(true);
|
||||
const afterUnset = loadSessionStore(storePath, { skipCache: true });
|
||||
const afterUnset = loadSessionStore(storePath);
|
||||
expect(
|
||||
(afterUnset["agent:main:main"] as unknown as Record<string, unknown>).approvalSnapshot,
|
||||
).toBeUndefined();
|
||||
@@ -162,11 +162,8 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ ok: true });
|
||||
expect(
|
||||
(
|
||||
loadSessionStore(storePath, { skipCache: true })[
|
||||
"agent:main:main"
|
||||
] as unknown as Record<string, unknown>
|
||||
).approvalSnapshot,
|
||||
(loadSessionStore(storePath)["agent:main:main"] as unknown as Record<string, unknown>)
|
||||
.approvalSnapshot,
|
||||
).toEqual({ state: "ready" });
|
||||
|
||||
await expect(
|
||||
@@ -178,9 +175,10 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
value: { state: "bad", fail: "throw" },
|
||||
}),
|
||||
).resolves.toMatchObject({ ok: true });
|
||||
const afterThrow = loadSessionStore(storePath, { skipCache: true })[
|
||||
"agent:main:main"
|
||||
] as unknown as Record<string, unknown>;
|
||||
const afterThrow = loadSessionStore(storePath)["agent:main:main"] as unknown as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
expect(afterThrow.approvalSnapshot).toBeUndefined();
|
||||
expect(afterThrow.pluginExtensions).toMatchObject({
|
||||
"failing-promoted-plugin": {
|
||||
@@ -198,11 +196,8 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ ok: true });
|
||||
expect(
|
||||
(
|
||||
loadSessionStore(storePath, { skipCache: true })[
|
||||
"agent:main:main"
|
||||
] as unknown as Record<string, unknown>
|
||||
).approvalSnapshot,
|
||||
(loadSessionStore(storePath)["agent:main:main"] as unknown as Record<string, unknown>)
|
||||
.approvalSnapshot,
|
||||
).toEqual({ state: "ready-again" });
|
||||
|
||||
await expect(
|
||||
@@ -214,9 +209,10 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
value: { state: "async-bad", fail: "promise" },
|
||||
}),
|
||||
).resolves.toMatchObject({ ok: true });
|
||||
const afterPromise = loadSessionStore(storePath, { skipCache: true })[
|
||||
"agent:main:main"
|
||||
] as unknown as Record<string, unknown>;
|
||||
const afterPromise = loadSessionStore(storePath)["agent:main:main"] as unknown as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
expect(afterPromise.approvalSnapshot).toBeUndefined();
|
||||
expect(afterPromise.pluginExtensions).toMatchObject({
|
||||
"failing-promoted-plugin": {
|
||||
@@ -416,7 +412,7 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ failures: [] });
|
||||
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
const entry = stored["agent:main:main"] as unknown as Record<string, unknown>;
|
||||
expect(entry.pluginExtensions).toBeUndefined();
|
||||
expect(entry.approvalSnapshot).toBeUndefined();
|
||||
@@ -483,7 +479,7 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ failures: [] });
|
||||
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
const entry = stored["agent:main:main"] as unknown as Record<string, unknown>;
|
||||
expect(entry.pluginExtensions).toBeUndefined();
|
||||
expect(entry.approvalSnapshot).toBeUndefined();
|
||||
@@ -562,7 +558,7 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ failures: [] });
|
||||
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
const entry = stored["agent:main:main"] as unknown as Record<string, unknown>;
|
||||
expect(entry.approvalSnapshot).toBeUndefined();
|
||||
expect(entry.pluginExtensionSlotKeys).toBeUndefined();
|
||||
@@ -665,7 +661,7 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ failures: [] });
|
||||
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
const entry = stored["agent:main:main"] as unknown as Record<string, unknown>;
|
||||
expect(entry.approvalSnapshot).toEqual({ state: "waiting" });
|
||||
expect(entry.legacyApprovalSnapshot).toBeUndefined();
|
||||
@@ -756,7 +752,7 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ failures: [] });
|
||||
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
const entry = stored["agent:main:main"] as unknown as Record<string, unknown>;
|
||||
expect(entry.approvalSnapshot).toEqual({ state: "waiting" });
|
||||
expect(entry.pluginExtensionSlotKeys).toEqual({
|
||||
@@ -820,7 +816,7 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
}),
|
||||
).resolves.toMatchObject({ failures: [] });
|
||||
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
const entry = stored["agent:main:main"] as unknown as Record<string, unknown>;
|
||||
expect(entry.approvalSnapshot).toBeUndefined();
|
||||
expect(entry.pluginExtensionSlotKeys).toBeUndefined();
|
||||
@@ -991,7 +987,7 @@ describe("plugin session extension SessionEntry projection", () => {
|
||||
value: { state: "executing" },
|
||||
});
|
||||
expect(result.ok).toBe(true);
|
||||
const stored = loadSessionStore(storePath, { skipCache: true });
|
||||
const stored = loadSessionStore(storePath);
|
||||
const entry = stored["agent:main:main"] as unknown as Record<string, unknown>;
|
||||
expect(entry.approvalSnapshot).toBeUndefined();
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user