Files
letta-code/src/tests/cli/prepareMessageHistory.test.ts
2026-02-21 12:27:20 -08:00

106 lines
3.4 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import type { Message } from "@letta-ai/letta-client/resources/agents/messages";
import { prepareMessageHistory } from "../../agent/check-approval";
function msg(
type: string,
id: string,
dateMs: number,
extra?: Record<string, unknown>,
): Message {
return {
id,
message_type: type,
date: new Date(dateMs).toISOString(),
...(extra ?? {}),
} as unknown as Message;
}
describe("prepareMessageHistory", () => {
test("primaryOnly returns only primary message types", () => {
const base = 1_700_000_000_000;
const messages: Message[] = [
msg("user_message", "u1", base + 1),
msg("tool_call_message", "tc1", base + 2),
msg("approval_request_message", "ar1", base + 3),
msg("tool_return_message", "tr1", base + 4),
msg("assistant_message", "a1", base + 5),
msg("reasoning_message", "r1", base + 6),
msg("approval_response_message", "ap1", base + 7),
msg("event_message", "e1", base + 8),
msg("summary_message", "s1", base + 9),
];
const out = prepareMessageHistory(messages, { primaryOnly: true });
expect(out.map((m) => m.message_type)).toEqual([
"user_message",
"assistant_message",
"event_message",
"summary_message",
]);
});
test("primaryOnly includes most recent assistant even if last N primary messages lack it", () => {
const base = 1_700_000_000_000;
const messages: Message[] = [];
// An older assistant message, then many user/event messages.
messages.push(msg("assistant_message", "a1", base + 1));
for (let i = 0; i < 30; i += 1) {
messages.push(msg("user_message", `u${i}`, base + 10 + i));
}
const out = prepareMessageHistory(messages, { primaryOnly: true });
expect(out.some((m) => m.message_type === "assistant_message")).toBe(true);
expect(
out.every((m) =>
[
"user_message",
"assistant_message",
"event_message",
"summary_message",
].includes(m.message_type as string),
),
).toBe(true);
});
test("primaryOnly falls back to reasoning when no primary messages exist", () => {
const base = 1_700_000_000_000;
const messages: Message[] = [
msg("tool_return_message", "tr1", base + 1),
msg("reasoning_message", "r1", base + 2),
msg("tool_return_message", "tr2", base + 3),
msg("reasoning_message", "r2", base + 4),
];
const out = prepareMessageHistory(messages, { primaryOnly: true });
expect(out.map((m) => m.message_type)).toEqual([
"reasoning_message",
"reasoning_message",
]);
});
test("primaryOnly returns [] when no primary or reasoning messages exist", () => {
const base = 1_700_000_000_000;
const messages: Message[] = [
msg("tool_return_message", "tr1", base + 1),
msg("approval_request_message", "ar1", base + 2),
msg("approval_response_message", "ap1", base + 3),
];
const out = prepareMessageHistory(messages, { primaryOnly: true });
expect(out).toEqual([]);
});
test("non-primaryOnly skips orphaned leading tool_return_message", () => {
const base = 1_700_000_000_000;
const messages: Message[] = [
msg("tool_return_message", "tr1", base + 1),
msg("assistant_message", "a1", base + 2),
];
const out = prepareMessageHistory(messages);
expect(out[0]?.message_type).toBe("assistant_message");
});
});