feat: add client-side sleeptime settings + compaction reflection triggers (#923)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import type { LettaStreamingResponse } from "@letta-ai/letta-client/resources/agents/messages";
|
||||
import { createBuffers, onChunk } from "../../cli/helpers/accumulator";
|
||||
import { createContextTracker } from "../../cli/helpers/contextTracker";
|
||||
|
||||
function usageChunk(
|
||||
fields: Record<string, number | null | undefined>,
|
||||
@@ -72,4 +73,36 @@ describe("accumulator usage statistics", () => {
|
||||
expect(buffers.usage.reasoningTokens).toBe(0);
|
||||
expect(buffers.usage.contextTokens).toBeUndefined();
|
||||
});
|
||||
|
||||
test("sets reflection trigger only after compaction summary message", () => {
|
||||
const buffers = createBuffers("agent-1");
|
||||
const tracker = createContextTracker();
|
||||
|
||||
onChunk(
|
||||
buffers,
|
||||
{
|
||||
message_type: "event_message",
|
||||
otid: "evt-compaction-1",
|
||||
event_type: "compaction",
|
||||
event_data: {},
|
||||
},
|
||||
tracker,
|
||||
);
|
||||
|
||||
expect(tracker.pendingReflectionTrigger).toBe(false);
|
||||
|
||||
onChunk(
|
||||
buffers,
|
||||
{
|
||||
message_type: "summary_message",
|
||||
otid: "evt-compaction-1",
|
||||
summary: "Compaction completed",
|
||||
},
|
||||
tracker,
|
||||
);
|
||||
|
||||
expect(tracker.pendingCompaction).toBe(true);
|
||||
expect(tracker.pendingSkillsReinject).toBe(true);
|
||||
expect(tracker.pendingReflectionTrigger).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
28
src/tests/cli/contextTracker.test.ts
Normal file
28
src/tests/cli/contextTracker.test.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import {
|
||||
createContextTracker,
|
||||
resetContextHistory,
|
||||
} from "../../cli/helpers/contextTracker";
|
||||
|
||||
describe("contextTracker", () => {
|
||||
test("resetContextHistory clears token history and pending compaction flags", () => {
|
||||
const tracker = createContextTracker();
|
||||
tracker.lastContextTokens = 123;
|
||||
tracker.contextTokensHistory = [
|
||||
{ timestamp: 1, tokens: 111, turnId: 1, compacted: true },
|
||||
];
|
||||
tracker.pendingCompaction = true;
|
||||
tracker.pendingSkillsReinject = true;
|
||||
tracker.pendingReflectionTrigger = true;
|
||||
tracker.currentTurnId = 9;
|
||||
|
||||
resetContextHistory(tracker);
|
||||
|
||||
expect(tracker.lastContextTokens).toBe(0);
|
||||
expect(tracker.contextTokensHistory).toEqual([]);
|
||||
expect(tracker.pendingCompaction).toBe(false);
|
||||
expect(tracker.pendingSkillsReinject).toBe(false);
|
||||
expect(tracker.pendingReflectionTrigger).toBe(false);
|
||||
expect(tracker.currentTurnId).toBe(9);
|
||||
});
|
||||
});
|
||||
147
src/tests/cli/memoryReminder.test.ts
Normal file
147
src/tests/cli/memoryReminder.test.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { afterEach, describe, expect, test } from "bun:test";
|
||||
import {
|
||||
MEMORY_CHECK_REMINDER,
|
||||
MEMORY_REFLECTION_REMINDER,
|
||||
} from "../../agent/promptAssets";
|
||||
import {
|
||||
buildCompactionMemoryReminder,
|
||||
buildMemoryReminder,
|
||||
getReflectionSettings,
|
||||
reflectionSettingsToLegacyMode,
|
||||
} from "../../cli/helpers/memoryReminder";
|
||||
import { settingsManager } from "../../settings-manager";
|
||||
|
||||
const originalGetLocalProjectSettings = settingsManager.getLocalProjectSettings;
|
||||
const originalGetSettings = settingsManager.getSettings;
|
||||
const originalIsMemfsEnabled = settingsManager.isMemfsEnabled;
|
||||
|
||||
afterEach(() => {
|
||||
(settingsManager as typeof settingsManager).getLocalProjectSettings =
|
||||
originalGetLocalProjectSettings;
|
||||
(settingsManager as typeof settingsManager).getSettings = originalGetSettings;
|
||||
(settingsManager as typeof settingsManager).isMemfsEnabled =
|
||||
originalIsMemfsEnabled;
|
||||
});
|
||||
|
||||
describe("memoryReminder", () => {
|
||||
test("prefers local reflection settings over global", () => {
|
||||
(settingsManager as typeof settingsManager).getLocalProjectSettings = () =>
|
||||
({
|
||||
reflectionTrigger: "compaction-event",
|
||||
reflectionBehavior: "auto-launch",
|
||||
reflectionStepCount: 33,
|
||||
}) as ReturnType<typeof settingsManager.getLocalProjectSettings>;
|
||||
(settingsManager as typeof settingsManager).getSettings = (() =>
|
||||
({
|
||||
memoryReminderInterval: 5,
|
||||
reflectionTrigger: "step-count",
|
||||
reflectionBehavior: "reminder",
|
||||
reflectionStepCount: 25,
|
||||
}) as ReturnType<
|
||||
typeof settingsManager.getSettings
|
||||
>) as typeof settingsManager.getSettings;
|
||||
|
||||
expect(getReflectionSettings()).toEqual({
|
||||
trigger: "compaction-event",
|
||||
behavior: "auto-launch",
|
||||
stepCount: 33,
|
||||
});
|
||||
});
|
||||
|
||||
test("falls back to legacy local mode when split fields are absent", () => {
|
||||
(settingsManager as typeof settingsManager).getLocalProjectSettings = () =>
|
||||
({
|
||||
memoryReminderInterval: "compaction",
|
||||
}) as ReturnType<typeof settingsManager.getLocalProjectSettings>;
|
||||
(settingsManager as typeof settingsManager).getSettings = (() =>
|
||||
({
|
||||
memoryReminderInterval: 5,
|
||||
reflectionTrigger: "step-count",
|
||||
reflectionBehavior: "reminder",
|
||||
reflectionStepCount: 25,
|
||||
}) as ReturnType<
|
||||
typeof settingsManager.getSettings
|
||||
>) as typeof settingsManager.getSettings;
|
||||
|
||||
expect(getReflectionSettings()).toEqual({
|
||||
trigger: "compaction-event",
|
||||
behavior: "reminder",
|
||||
stepCount: 25,
|
||||
});
|
||||
});
|
||||
|
||||
test("disables turn-based reminders for non-step-count trigger", async () => {
|
||||
(settingsManager as typeof settingsManager).getLocalProjectSettings = () =>
|
||||
({
|
||||
reflectionTrigger: "compaction-event",
|
||||
reflectionBehavior: "reminder",
|
||||
}) as ReturnType<typeof settingsManager.getLocalProjectSettings>;
|
||||
(settingsManager as typeof settingsManager).getSettings = (() =>
|
||||
({
|
||||
memoryReminderInterval: 5,
|
||||
reflectionTrigger: "step-count",
|
||||
reflectionBehavior: "reminder",
|
||||
reflectionStepCount: 25,
|
||||
}) as ReturnType<
|
||||
typeof settingsManager.getSettings
|
||||
>) as typeof settingsManager.getSettings;
|
||||
|
||||
const reminder = await buildMemoryReminder(10, "agent-1");
|
||||
expect(reminder).toBe("");
|
||||
});
|
||||
|
||||
test("keeps existing numeric interval behavior", async () => {
|
||||
(settingsManager as typeof settingsManager).getLocalProjectSettings = () =>
|
||||
({
|
||||
reflectionTrigger: "step-count",
|
||||
reflectionBehavior: "auto-launch",
|
||||
reflectionStepCount: 5,
|
||||
}) as ReturnType<typeof settingsManager.getLocalProjectSettings>;
|
||||
(settingsManager as typeof settingsManager).getSettings = (() =>
|
||||
({
|
||||
memoryReminderInterval: 10,
|
||||
reflectionTrigger: "step-count",
|
||||
reflectionBehavior: "reminder",
|
||||
reflectionStepCount: 25,
|
||||
}) as ReturnType<
|
||||
typeof settingsManager.getSettings
|
||||
>) as typeof settingsManager.getSettings;
|
||||
(settingsManager as typeof settingsManager).isMemfsEnabled = (() =>
|
||||
false) as typeof settingsManager.isMemfsEnabled;
|
||||
|
||||
const reminder = await buildMemoryReminder(10, "agent-1");
|
||||
expect(reminder).toBe(MEMORY_CHECK_REMINDER);
|
||||
});
|
||||
|
||||
test("maps split reflection settings back to legacy mode", () => {
|
||||
expect(
|
||||
reflectionSettingsToLegacyMode({
|
||||
trigger: "off",
|
||||
behavior: "reminder",
|
||||
stepCount: 25,
|
||||
}),
|
||||
).toBeNull();
|
||||
expect(
|
||||
reflectionSettingsToLegacyMode({
|
||||
trigger: "step-count",
|
||||
behavior: "auto-launch",
|
||||
stepCount: 30,
|
||||
}),
|
||||
).toBe(30);
|
||||
expect(
|
||||
reflectionSettingsToLegacyMode({
|
||||
trigger: "compaction-event",
|
||||
behavior: "auto-launch",
|
||||
stepCount: 25,
|
||||
}),
|
||||
).toBe("auto-compaction");
|
||||
});
|
||||
|
||||
test("builds compaction reminder with memfs-aware reflection content", async () => {
|
||||
(settingsManager as typeof settingsManager).isMemfsEnabled = (() =>
|
||||
true) as typeof settingsManager.isMemfsEnabled;
|
||||
|
||||
const reminder = await buildCompactionMemoryReminder("agent-1");
|
||||
expect(reminder).toBe(MEMORY_REFLECTION_REMINDER);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user