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
3 changes: 3 additions & 0 deletions app/chat/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
showChartWorkspaceAtom,
showDatasetWorkspaceAtom,
showFileWorkspaceAtom,
showMarkdownWorkspaceAtom,
vncUrlAtom,
workspaceChartAtom,
workspaceDatasetAtom,
Expand Down Expand Up @@ -346,6 +347,8 @@ const ChatPage = ({ params }: ChatPageProps) => {
filename: artifact.filename,
});
}
} else if (artifact.markdownContent) {
jotaiStore.set(showMarkdownWorkspaceAtom, artifact.markdownContent);
} else if (artifact.fileId && artifact.filename) {
jotaiStore.set(showFileWorkspaceAtom, {
downloadUrl: getFileDownloadUrl(
Expand Down
38 changes: 38 additions & 0 deletions app/chat/components/assistant-message-round-artifacts.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,21 @@ const assistantMessageWithMultipleCharts = {
],
} as unknown as UIMessage;

const assistantMessageWithInlineReport = {
id: "assistant-round-inline-report",
role: "assistant",
parts: [
{
type: "text",
text: "Report completed",
},
{
type: "markdown-content",
content: "# Analysis Report\n\nRevenue increased by 12%.",
},
],
} as unknown as UIMessage;

describe("AssistantMessage round artifact actions", () => {
it("renders per-category buttons with icon prefix and opens the selected artifact", () => {
const onSelectRoundArtifact = jest.fn();
Expand Down Expand Up @@ -147,4 +162,27 @@ describe("AssistantMessage round artifact actions", () => {

expect(screen.getByText("CSV 312 Bytes")).toBeInTheDocument();
});

it("renders inline markdown report as a round artifact action", () => {
const onSelectRoundArtifact = jest.fn();

render(
<MessageItem
message={assistantMessageWithInlineReport}
thinkingTime={null}
hasToolCalls={false}
onSelectRoundArtifact={onSelectRoundArtifact}
/>,
);

fireEvent.click(screen.getByRole("button", { name: /Report/i }));

expect(onSelectRoundArtifact).toHaveBeenCalledWith(
expect.objectContaining<Partial<WorkspaceRoundArtifact>>({
category: "report",
label: "Analysis Report",
markdownContent: "# Analysis Report\n\nRevenue increased by 12%.",
}),
);
});
});
24 changes: 24 additions & 0 deletions lib/chat/workspace-hydration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,28 @@ describe("workspace hydration", () => {
);
expect(snapshot.view).toBe("dataset");
});

it("derives report artifacts from inline markdown content", () => {
const assistantMessage: UIMessage = {
id: "assistant-inline-report",
role: "assistant",
parts: [
{
type: "markdown-content",
content: "# Analysis Report\n\nRevenue increased by 12%.",
} as unknown as UIMessage["parts"][number],
],
};

const artifacts = deriveRoundArtifactsFromMessage(assistantMessage);

expect(artifacts.report).toHaveLength(1);
expect(artifacts.report[0]).toEqual(
expect.objectContaining({
category: "report",
label: "Analysis Report",
markdownContent: "# Analysis Report\n\nRevenue increased by 12%.",
}),
);
});
});
35 changes: 35 additions & 0 deletions lib/chat/workspace-hydration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type WorkspaceRoundArtifact = {
downloadUrl?: string;
extension?: string;
chart?: Record<string, unknown>;
markdownContent?: string;
title?: string;
toolCallId?: string;
};
Expand Down Expand Up @@ -100,6 +101,16 @@ const getFileDownloadUrl = (
return undefined;
};

const getMarkdownReportLabel = (content: string): string => {
const heading = content
.split("\n")
.map((line) => line.trim())
.find((line) => line.startsWith("#"));
const normalizedHeading = heading?.replace(/^#+\s*/, "").trim();

return normalizedHeading || "Generated report";
};

// Resolve dataset attachments from user metadata even when preview is omitted.
const resolveDatasetAttachment = (
attachments: ChatAttachment[] | undefined,
Expand Down Expand Up @@ -284,6 +295,25 @@ const deriveRoundArtifactsFromMessage = (
continue;
}

if (
partRecord.type === "markdown-content" &&
typeof partRecord.content === "string" &&
partRecord.content.trim().length > 0
) {
const createdAt = nextCreatedAt();
const markdownContent = partRecord.content.trim();
const label = getMarkdownReportLabel(markdownContent);
pushRoundArtifact(artifacts, {
id: `${message.id}-report-markdown-${createdAt}`,
category: "report",
createdAt,
label,
markdownContent,
title: label,
});
continue;
}

if (
typeof partRecord.type !== "string" ||
!partRecord.type.startsWith("tool-")
Expand Down Expand Up @@ -539,6 +569,11 @@ const deriveWorkspaceSnapshotFromMessages = (
}

if (artifact.category === "report") {
if (artifact.markdownContent) {
snapshot.markdownContent = artifact.markdownContent;
markViewUpdated("markdown");
continue;
}
if (!artifact.fileId || !artifact.filename) {
continue;
}
Expand Down
Loading