Preserve normalized chat lines during history merges

This commit is contained in:
Federico Jaramillo Martinez
2026-05-11 23:07:12 +02:00
parent d7dc18a6ec
commit 70b079d3c3
2 changed files with 14 additions and 0 deletions
+7
View File
@@ -13,6 +13,13 @@ describe("chat message normalization", () => {
]);
});
it("preserves already-normalized chat lines", () => {
const line = { role: "assistant" as const, parts: [{ type: "text" as const, text: "cached" }] };
expect(normalizeMessage(line)).toEqual([line]);
expect(normalizeMessages([{ role: "user", content: "raw" }, line])).toEqual([textMessage("user", "raw"), line]);
});
it("normalizes tool calls and tool results", () => {
expect(normalizeMessage({ role: "assistant", content: [{ type: "toolCall", name: "bash", arguments: { command: "npm test" } }] })).toEqual([
{ role: "assistant", parts: [{ type: "toolCall", toolName: "bash", summary: "npm test" }] },
+7
View File
@@ -42,6 +42,7 @@ export function appendThinking(messages: ChatLine[], text: string): ChatLine[] {
}
export function normalizeMessage(message: unknown): ChatLine[] {
if (isChatLine(message)) return [message];
if (getString(message, "role") === "bashExecution") return [withMessageMeta(normalizeBashExecution(message), message)];
const role = normalizeRole(getString(message, "role"));
const parts = normalizeContent(getProperty(message, "content"), message);
@@ -55,6 +56,12 @@ export function normalizeMessage(message: unknown): ChatLine[] {
return visible.length > 0 ? [withMessageMeta({ role: displayRole, parts: visible, ...(source === undefined ? {} : { source }) }, message)] : [];
}
function isChatLine(message: unknown): message is ChatLine {
const role = getString(message, "role");
return (role === "user" || role === "assistant" || role === "tool" || role === "system" || role === "bash" || role === "skill")
&& Array.isArray(getProperty(message, "parts"));
}
function normalizeSkillInvocation(parts: ChatPart[]): ChatLine[] | undefined {
if (parts.length !== 1 || parts[0]?.type !== "text") return undefined;
const skill = parseSkillBlock(parts[0].text);