fix: tighten session entry updates
Co-authored-by: Tyler Yust <tyler6204@users.noreply.github.com>
This commit is contained in:
@@ -1,15 +1,22 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const loadSessionStoreMock = vi.fn();
|
||||
const saveSessionStoreMock = vi.fn();
|
||||
const updateSessionStoreMock = vi.fn();
|
||||
|
||||
vi.mock("../config/sessions.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../config/sessions.js")>();
|
||||
return {
|
||||
...actual,
|
||||
loadSessionStore: (storePath: string) => loadSessionStoreMock(storePath),
|
||||
saveSessionStore: (storePath: string, store: Record<string, unknown>) =>
|
||||
saveSessionStoreMock(storePath, store),
|
||||
updateSessionStore: async (
|
||||
storePath: string,
|
||||
mutator: (store: Record<string, unknown>) => Promise<void> | void,
|
||||
) => {
|
||||
const store = loadSessionStoreMock(storePath) as Record<string, unknown>;
|
||||
await mutator(store);
|
||||
updateSessionStoreMock(storePath, store);
|
||||
return store;
|
||||
},
|
||||
resolveStorePath: () => "/tmp/sessions.json",
|
||||
};
|
||||
});
|
||||
@@ -73,7 +80,7 @@ import { createClawdbotTools } from "./clawdbot-tools.js";
|
||||
describe("session_status tool", () => {
|
||||
it("returns a status card for the current session", async () => {
|
||||
loadSessionStoreMock.mockReset();
|
||||
saveSessionStoreMock.mockReset();
|
||||
updateSessionStoreMock.mockReset();
|
||||
loadSessionStoreMock.mockReturnValue({
|
||||
main: {
|
||||
sessionId: "s1",
|
||||
@@ -96,7 +103,7 @@ describe("session_status tool", () => {
|
||||
|
||||
it("errors for unknown session keys", async () => {
|
||||
loadSessionStoreMock.mockReset();
|
||||
saveSessionStoreMock.mockReset();
|
||||
updateSessionStoreMock.mockReset();
|
||||
loadSessionStoreMock.mockReturnValue({
|
||||
main: { sessionId: "s1", updatedAt: 10 },
|
||||
});
|
||||
@@ -110,12 +117,12 @@ describe("session_status tool", () => {
|
||||
await expect(tool.execute("call2", { sessionKey: "nope" })).rejects.toThrow(
|
||||
"Unknown sessionKey",
|
||||
);
|
||||
expect(saveSessionStoreMock).not.toHaveBeenCalled();
|
||||
expect(updateSessionStoreMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("resets per-session model override via model=default", async () => {
|
||||
loadSessionStoreMock.mockReset();
|
||||
saveSessionStoreMock.mockReset();
|
||||
updateSessionStoreMock.mockReset();
|
||||
loadSessionStoreMock.mockReturnValue({
|
||||
main: {
|
||||
sessionId: "s1",
|
||||
@@ -133,8 +140,8 @@ describe("session_status tool", () => {
|
||||
if (!tool) throw new Error("missing session_status tool");
|
||||
|
||||
await tool.execute("call3", { model: "default" });
|
||||
expect(saveSessionStoreMock).toHaveBeenCalled();
|
||||
const [, savedStore] = saveSessionStoreMock.mock.calls.at(-1) as [
|
||||
expect(updateSessionStoreMock).toHaveBeenCalled();
|
||||
const [, savedStore] = updateSessionStoreMock.mock.calls.at(-1) as [
|
||||
string,
|
||||
Record<string, unknown>,
|
||||
];
|
||||
|
||||
@@ -400,6 +400,9 @@ export async function runAgentTurnWithFallback(params: {
|
||||
}
|
||||
}
|
||||
|
||||
// Keep the in-memory snapshot consistent with the on-disk store reset.
|
||||
delete params.activeSessionStore[sessionKey];
|
||||
|
||||
// Remove session entry from store using a fresh, locked snapshot.
|
||||
await updateSessionStore(params.storePath, (store) => {
|
||||
delete store[sessionKey];
|
||||
|
||||
@@ -243,6 +243,7 @@ export async function agentCommand(
|
||||
}
|
||||
|
||||
if (sessionEntry && sessionStore && sessionKey && hasStoredOverride) {
|
||||
const entry = sessionEntry;
|
||||
const overrideProvider = sessionEntry.providerOverride?.trim() || defaultProvider;
|
||||
const overrideModel = sessionEntry.modelOverride?.trim();
|
||||
if (overrideModel) {
|
||||
@@ -252,12 +253,12 @@ export async function agentCommand(
|
||||
allowedModelKeys.size > 0 &&
|
||||
!allowedModelKeys.has(key)
|
||||
) {
|
||||
delete sessionEntry.providerOverride;
|
||||
delete sessionEntry.modelOverride;
|
||||
sessionEntry.updatedAt = Date.now();
|
||||
sessionStore[sessionKey] = sessionEntry;
|
||||
delete entry.providerOverride;
|
||||
delete entry.modelOverride;
|
||||
entry.updatedAt = Date.now();
|
||||
sessionStore[sessionKey] = entry;
|
||||
await updateSessionStore(storePath, (store) => {
|
||||
store[sessionKey] = sessionEntry;
|
||||
store[sessionKey] = entry;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -277,17 +278,21 @@ export async function agentCommand(
|
||||
model = storedModelOverride;
|
||||
}
|
||||
}
|
||||
if (sessionEntry?.authProfileOverride) {
|
||||
const store = ensureAuthProfileStore();
|
||||
const profile = store.profiles[sessionEntry.authProfileOverride];
|
||||
if (!profile || profile.provider !== provider) {
|
||||
delete sessionEntry.authProfileOverride;
|
||||
sessionEntry.updatedAt = Date.now();
|
||||
if (sessionStore && sessionKey) {
|
||||
sessionStore[sessionKey] = sessionEntry;
|
||||
await updateSessionStore(storePath, (store) => {
|
||||
store[sessionKey] = sessionEntry;
|
||||
});
|
||||
if (sessionEntry) {
|
||||
const authProfileId = sessionEntry.authProfileOverride;
|
||||
if (authProfileId) {
|
||||
const entry = sessionEntry;
|
||||
const store = ensureAuthProfileStore();
|
||||
const profile = store.profiles[authProfileId];
|
||||
if (!profile || profile.provider !== provider) {
|
||||
delete entry.authProfileOverride;
|
||||
entry.updatedAt = Date.now();
|
||||
if (sessionStore && sessionKey) {
|
||||
sessionStore[sessionKey] = entry;
|
||||
await updateSessionStore(storePath, (store) => {
|
||||
store[sessionKey] = entry;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,11 +317,12 @@ export async function agentCommand(
|
||||
}
|
||||
resolvedThinkLevel = "high";
|
||||
if (sessionEntry && sessionStore && sessionKey && sessionEntry.thinkingLevel === "xhigh") {
|
||||
sessionEntry.thinkingLevel = "high";
|
||||
sessionEntry.updatedAt = Date.now();
|
||||
sessionStore[sessionKey] = sessionEntry;
|
||||
const entry = sessionEntry;
|
||||
entry.thinkingLevel = "high";
|
||||
entry.updatedAt = Date.now();
|
||||
sessionStore[sessionKey] = entry;
|
||||
await updateSessionStore(storePath, (store) => {
|
||||
store[sessionKey] = sessionEntry;
|
||||
store[sessionKey] = entry;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,11 +136,6 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
|
||||
publicKey: "a",
|
||||
token,
|
||||
autoDeploy: nativeEnabled,
|
||||
eventQueue: {
|
||||
// Auto-threading (create thread + generate reply + post) can exceed the default
|
||||
// 30s listener timeout in some environments.
|
||||
listenerTimeout: 120_000,
|
||||
},
|
||||
},
|
||||
{
|
||||
commands,
|
||||
|
||||
Reference in New Issue
Block a user