fix: stabilize flaky tests and sanitize directive-only chat tags

This commit is contained in:
Peter Steinberger
2026-02-22 12:18:13 +01:00
parent 3700151ec0
commit 78c3c2a542
9 changed files with 161 additions and 77 deletions

View File

@@ -1,5 +1,8 @@
import { describe, expect, test } from "vitest";
import { stripInlineDirectiveTagsForDisplay } from "./directive-tags.js";
import {
stripInlineDirectiveTagsForDisplay,
stripInlineDirectiveTagsFromMessageForDisplay,
} from "./directive-tags.js";
describe("stripInlineDirectiveTagsForDisplay", () => {
test("removes reply and audio directives", () => {
@@ -23,3 +26,34 @@ describe("stripInlineDirectiveTagsForDisplay", () => {
expect(result.text).toBe(input);
});
});
describe("stripInlineDirectiveTagsFromMessageForDisplay", () => {
test("strips inline directives from text content blocks", () => {
const input = {
role: "assistant",
content: [{ type: "text", text: "hello [[reply_to_current]] world [[audio_as_voice]]" }],
};
const result = stripInlineDirectiveTagsFromMessageForDisplay(input);
expect(result).toBeDefined();
expect(result?.content).toEqual([{ type: "text", text: "hello world " }]);
});
test("preserves empty-string text when directives are entire content", () => {
const input = {
role: "assistant",
content: [{ type: "text", text: "[[reply_to_current]]" }],
};
const result = stripInlineDirectiveTagsFromMessageForDisplay(input);
expect(result).toBeDefined();
expect(result?.content).toEqual([{ type: "text", text: "" }]);
});
test("returns original message when content is not an array", () => {
const input = {
role: "assistant",
content: "plain text",
};
const result = stripInlineDirectiveTagsFromMessageForDisplay(input);
expect(result).toEqual(input);
});
});

View File

@@ -29,6 +29,17 @@ type StripInlineDirectiveTagsResult = {
changed: boolean;
};
type MessageTextPart = {
type: "text";
text: string;
} & Record<string, unknown>;
type MessagePart = Record<string, unknown> | null | undefined;
export type DisplayMessageWithContent = {
content?: unknown;
} & Record<string, unknown>;
export function stripInlineDirectiveTagsForDisplay(text: string): StripInlineDirectiveTagsResult {
if (!text) {
return { text, changed: false };
@@ -41,6 +52,36 @@ export function stripInlineDirectiveTagsForDisplay(text: string): StripInlineDir
};
}
function isMessageTextPart(part: MessagePart): part is MessageTextPart {
return Boolean(part) && part?.type === "text" && typeof part.text === "string";
}
/**
* Strips inline directive tags from message text blocks while preserving message shape.
* Empty post-strip text stays empty-string to preserve caller semantics.
*/
export function stripInlineDirectiveTagsFromMessageForDisplay(
message: DisplayMessageWithContent | undefined,
): DisplayMessageWithContent | undefined {
if (!message) {
return message;
}
if (!Array.isArray(message.content)) {
return message;
}
const cleaned = message.content.map((part) => {
if (!part || typeof part !== "object") {
return part;
}
const record = part as MessagePart;
if (!isMessageTextPart(record)) {
return part;
}
return { ...record, text: stripInlineDirectiveTagsForDisplay(record.text).text };
});
return { ...message, content: cleaned };
}
export function parseInlineDirectives(
text?: string,
options: InlineDirectiveParseOptions = {},