test: cover conversation context edge cases
This commit is contained in:
@@ -3,7 +3,6 @@ import { getDatabase } from "../database/drizzle";
|
|||||||
import { attachmentsTable, messagesTable } from "../database/schema";
|
import { attachmentsTable, messagesTable } from "../database/schema";
|
||||||
import { createChildLogger } from "../logger";
|
import { createChildLogger } from "../logger";
|
||||||
import type {
|
import type {
|
||||||
AIStatus,
|
|
||||||
AttachmentRecord,
|
AttachmentRecord,
|
||||||
MessageQuery,
|
MessageQuery,
|
||||||
MessageRecord,
|
MessageRecord,
|
||||||
|
|||||||
@@ -59,4 +59,88 @@ describe("buildConversationPromptMessages", () => {
|
|||||||
expect(lines.some((line) => line.includes("edited"))).toBe(true);
|
expect(lines.some((line) => line.includes("edited"))).toBe(true);
|
||||||
expect(lines.some((line) => line.includes("original"))).toBe(false);
|
expect(lines.some((line) => line.includes("original"))).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("empty targets returns only fitting context or empty string if no context", () => {
|
||||||
|
// Case 1: No context, no targets
|
||||||
|
const lines1 = buildConversationPromptMessages({
|
||||||
|
contextBefore: [],
|
||||||
|
targets: [],
|
||||||
|
maxTokens: 1000,
|
||||||
|
});
|
||||||
|
expect(lines1).toEqual([]);
|
||||||
|
|
||||||
|
// Case 2: Context but no targets
|
||||||
|
const lines2 = buildConversationPromptMessages({
|
||||||
|
contextBefore: [message("a", "hello", 1)],
|
||||||
|
targets: [],
|
||||||
|
maxTokens: 1000,
|
||||||
|
});
|
||||||
|
expect(lines2).toHaveLength(1);
|
||||||
|
expect(lines2[0]).toContain("[context]");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("maxTokens budget includes target lines even when targets exceed budget", () => {
|
||||||
|
// Create targets that exceed budget
|
||||||
|
const longContent = "x".repeat(500); // ~125 tokens
|
||||||
|
const targets = [
|
||||||
|
message("t1", longContent, 1),
|
||||||
|
message("t2", longContent, 2),
|
||||||
|
message("t3", longContent, 3),
|
||||||
|
];
|
||||||
|
|
||||||
|
const lines = buildConversationPromptMessages({
|
||||||
|
contextBefore: [message("c1", "context", 0)],
|
||||||
|
targets,
|
||||||
|
maxTokens: 200, // Only 200 tokens, but targets alone are ~375
|
||||||
|
});
|
||||||
|
|
||||||
|
// All targets should be included
|
||||||
|
expect(lines.some((line) => line.includes("id=t1"))).toBe(true);
|
||||||
|
expect(lines.some((line) => line.includes("id=t2"))).toBe(true);
|
||||||
|
expect(lines.some((line) => line.includes("id=t3"))).toBe(true);
|
||||||
|
|
||||||
|
// Context should be excluded due to budget
|
||||||
|
expect(lines.some((line) => line.includes("id=c1"))).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("most recent context is kept when context budget is tight", () => {
|
||||||
|
// Create multiple context messages with different timestamps
|
||||||
|
// Use longer content to ensure they consume meaningful tokens
|
||||||
|
const contextBefore = [
|
||||||
|
message(
|
||||||
|
"c1",
|
||||||
|
"oldest context with some extra words to make it longer",
|
||||||
|
1000,
|
||||||
|
),
|
||||||
|
message(
|
||||||
|
"c2",
|
||||||
|
"middle context with some extra words to make it longer",
|
||||||
|
2000,
|
||||||
|
),
|
||||||
|
message(
|
||||||
|
"c3",
|
||||||
|
"newest context with some extra words to make it longer",
|
||||||
|
3000,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
const lines = buildConversationPromptMessages({
|
||||||
|
contextBefore,
|
||||||
|
targets: [message("t1", "target message", 4000)],
|
||||||
|
maxTokens: 90, // Very tight budget: target ~35 tokens, room for ~55 tokens of context (fits only c3)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Should include target
|
||||||
|
expect(lines.some((line) => line.includes("id=t1"))).toBe(true);
|
||||||
|
|
||||||
|
// Should include newest context (c3) but not oldest (c1)
|
||||||
|
// With tight budget, only the most recent context should fit
|
||||||
|
expect(lines.some((line) => line.includes("id=c3"))).toBe(true);
|
||||||
|
expect(lines.some((line) => line.includes("id=c1"))).toBe(false);
|
||||||
|
|
||||||
|
// Verify chronological order is maintained
|
||||||
|
const indexT1 = lines.findIndex((line) => line.includes("id=t1"));
|
||||||
|
const indexC3 = lines.findIndex((line) => line.includes("id=c3"));
|
||||||
|
expect(indexC3).toBeLessThan(indexT1); // context before target
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user