Skip to content
Closed
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
43 changes: 42 additions & 1 deletion apps/web/src/components/chat/MessagesTimeline.browser.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import "~/index.css";

import { act, render } from "../../../test/render";
import { MessagesTimeline } from "./MessagesTimeline";
import { remarkThoughtPreview } from "./TimelineWorkEntryRow.logic";
import { remarkThoughtPreview, thoughtPreviewSource } from "./TimelineWorkEntryRow.logic";
import { parseMarkdownWithMath } from "@t3tools/shared/markdownMath";
import { collectThreadFindRanges } from "./threadFindHighlights";

Expand Down Expand Up @@ -368,6 +368,47 @@ describe("MessagesTimeline agent messages", () => {
});
});

describe("MessagesTimeline live reasoning", () => {
it("never cuts the label source inside an emoji", () => {
const source = thoughtPreviewSource(`${"a".repeat(1_499)}🙂 and more`);
expect(source).toBe("a".repeat(1_499));
});

it("labels an expanded live thought from its opening instead of the whole trace", async () => {
const runId = RunId.make("thinking-run");
const trace = `Checking the **parser** first. ${"Then the next file. ".repeat(1_000)}`;
await using screen = await renderTimeline(
[
{
kind: "work",
id: "thought",
createdAt: CREATED_AT,
entry: {
id: "thought",
runId,
createdAt: CREATED_AT,
label: "Thinking",
tone: "thinking",
itemType: "reasoning",
detail: trace,
toolLifecycleStatus: "inProgress",
},
},
],
{ isWorking: true, activeTurnInProgress: true, runningRunId: runId },
);
const row = () => screen.container.querySelector<HTMLElement>("button[aria-expanded]")!;
await click(row());
await vi.waitFor(() => {
expect(row().getAttribute("aria-expanded")).toBe("true");
const label = row().textContent ?? "";
expect(label.startsWith("Checking the parser first. Then the next file.")).toBe(true);
// The label is one truncated line, so streaming a long trace must not flatten all of it.
expect(label.length).toBeLessThan(trace.length / 4);
});
});
});

describe("compact reasoning math", () => {
it("keeps formulas while flattening compact reasoning previews", () => {
const tree = parseMarkdownWithMath("## Reasoning\n\nUse **norm** $|x|$ and \\[x^2\\]");
Expand Down
6 changes: 6 additions & 0 deletions apps/web/src/components/chat/TimelineWorkEntryRow.logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,12 @@ export function workEntryIconName(workEntry: TimelineWorkEntry): WorkEntryIconNa
return workToneIcon(workEntry.tone).iconName;
}

/** The preview is one truncated line; bound parsing work while long traces stream. */
export function thoughtPreviewSource(markdown: string): string {
// Drop a lone high surrogate so the cut never leaves half of an emoji.
return markdown.slice(0, 1_500).replace(/[\uD800-\uDBFF]$/, "");
}

/** Compact reasoning keeps formulas while flattening other Markdown into label text. */
export function remarkThoughtPreview(fallback: string) {
return (tree: Root) => {
Expand Down
3 changes: 2 additions & 1 deletion apps/web/src/components/chat/TimelineWorkEntryRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import {
buildToolCallExpandedBody,
workEntryIconName,
remarkThoughtPreview,
thoughtPreviewSource,
} from "./TimelineWorkEntryRow.logic";

export function useThreadReadTarget(entry: TimelineWorkEntry, environmentId: EnvironmentId) {
Expand Down Expand Up @@ -411,7 +412,7 @@ function WorkEntryLogRow(props: WorkEntryRowProps) {
{isReasoning && !expanded ? (
<ChatMarkdown
inline
text={workEntry.detail ?? previewText}
text={thoughtPreviewSource(workEntry.detail ?? previewText)}
cwd={ctx.markdownCwd}
parseRawHtml={false}
extraRemarkPlugins={[
Expand Down
3 changes: 2 additions & 1 deletion apps/web/src/components/chat/TimelineWorkGroupRows.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
} from "./TimelineWorkEntryRow";
import {
remarkThoughtPreview,
thoughtPreviewSource,
toolGroupSummaryIconName,
workEntryIconName,
} from "./TimelineWorkEntryRow.logic";
Expand Down Expand Up @@ -558,7 +559,7 @@ export function LiveWorkEntryTimelineRow({
) : row.entry.itemType === "reasoning" ? (
<ChatMarkdown
inline
text={row.entry.detail ?? label}
text={thoughtPreviewSource(row.entry.detail ?? label)}
cwd={ctx.markdownCwd}
parseRawHtml={false}
extraRemarkPlugins={[[remarkThoughtPreview, row.active ? "Thinking" : "Thought"]]}
Expand Down
Loading