Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions apps/web/src/components/chat/MessagesTimeline.browser.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,25 @@ describe("MessagesTimeline messages", () => {
expect((globalThis as { __t3Xss?: number }).__t3Xss).toBeUndefined();
});

it("keeps single tildes in user paths literal without changing double tildes or assistant text", async () => {
const source =
"Install the skill as ~/folder-a/skills/x, then follow the guide (~/folder-a/guide.md).";
await using screen = await renderTimeline([
message(source),
message("Drop ~~the old plan~~", {}, "message-2"),
message(source, { role: "assistant" }, "assistant-1"),
]);
const [user, doubleTilde, assistant] = screen.container.querySelectorAll<HTMLElement>(
"[data-timeline-row-kind=message]",
);
expect(user?.textContent).toContain(source);
expect(user?.querySelector("del")).toBeNull();
expect(doubleTilde?.querySelector("del")?.textContent).toBe("the old plan");
expect(assistant?.querySelector("del")?.textContent).toBe(
"/folder-a/skills/x, then follow the guide (",
);
});

it("renders sanitized raw HTML in assistant messages", async () => {
await using screen = await renderTimeline([
message(
Expand Down
10 changes: 8 additions & 2 deletions apps/web/src/components/chat/TimelineUserMessageRow.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { InlineAudioPreview } from "../files/InlineAudioPreview";
import { filePreviewKind } from "@t3tools/shared/filePreview";
import { remarkEnableOrderedListNumbers } from "@t3tools/shared/markdownPipeline";
import {
CHAT_USER_MARKDOWN_REMARK_PLUGINS,
remarkEnableOrderedListNumbers,
} from "@t3tools/shared/markdownPipeline";
import { findRevealRef } from "./markdownFindContext";
import {
type EnvironmentId,
Expand Down Expand Up @@ -1200,7 +1203,10 @@ const CollapsibleUserMessageBody = memo(function CollapsibleUserMessageBody(prop
);
});

const USER_MESSAGE_REMARK_PLUGINS = [remarkEnableOrderedListNumbers];
const USER_MESSAGE_REMARK_PLUGINS = [
...CHAT_USER_MARKDOWN_REMARK_PLUGINS,
remarkEnableOrderedListNumbers,
];

const UserMessageBody = memo(function UserMessageBody(props: {
text: string;
Expand Down
6 changes: 6 additions & 0 deletions packages/shared/src/markdownPipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,12 @@ export const CHAT_MARKDOWN_REMARK_PLUGINS_WITH_BREAKS: PluggableList = [
remarkNormalizeLinksAndTagInlineCode,
];

// Users type paths like ~/a and (~/b, which GFM's single-tilde strikethrough hides as <del>.
// Appended after the base list, this reconfigures its remark-gfm entry; ~~double~~ still strikes.
export const CHAT_USER_MARKDOWN_REMARK_PLUGINS: PluggableList = [
[remarkGfm, { singleTilde: false }],
];

// Start tags an HTML parser closes an open `<p>` for.
const CLOSES_PARAGRAPH = new Set(
"address article aside blockquote center details dialog dir div dl fieldset figcaption figure footer form h1 h2 h3 h4 h5 h6 header hgroup hr li listing main menu nav ol p plaintext pre search section summary table ul xmp dd dt".split(
Expand Down
8 changes: 8 additions & 0 deletions packages/shared/src/threadFindText.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ it("excludes review attachments rendered as context chips", () => {
]);
});

it("indexes single tildes in user paths as typed", () => {
const text = "Install as ~/a/x, then read (~/a/guide.md).";
expect(searchableMessageSegments({ role: "user", text, streaming: false })?.join("")).toBe(text);
expect(
searchableMessageSegments({ role: "user", text: "Drop ~~old~~", streaming: false })?.join(""),
).toBe("Drop old");
});

it("excludes structured context chips without joining text across them", () => {
expect(
searchableMessageSegments({
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/src/threadFindText.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
CHAT_MARKDOWN_REHYPE_PLUGINS,
CHAT_MARKDOWN_REMARK_PLUGINS,
CHAT_MARKDOWN_REMARK_PLUGINS_WITH_BREAKS,
CHAT_USER_MARKDOWN_REMARK_PLUGINS,
} from "./markdownPipeline.ts";

// Inline wrappers (including Shiki token spans) must not split a search phrase.
Expand Down Expand Up @@ -94,6 +95,7 @@ const insightBreaksProcessor = assistantTextProcessor(true, true);
const userProcessor = unified()
.use(remarkParse)
.use(CHAT_MARKDOWN_REMARK_PLUGINS_WITH_BREAKS)
.use(CHAT_USER_MARKDOWN_REMARK_PLUGINS)
.use(remarkRehype, { allowDangerousHtml: true });

interface TextTree {
Expand Down
Loading