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
47 changes: 46 additions & 1 deletion frontend/src/components/chat/acp/blocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,46 @@ import {
isUserMessages,
} from "./utils";

/**
* Merges consecutive text blocks into a single text block to prevent
* fragmented display when agent messages are streamed in chunks.
*/
function mergeConsecutiveTextBlocks(
contentBlocks: ContentBlock[],
): ContentBlock[] {
if (contentBlocks.length === 0) {
return contentBlocks;
}

const merged: ContentBlock[] = [];
let currentTextBlock: string | null = null;

for (const block of contentBlocks) {
if (block.type === "text") {
// Accumulate text content
if (currentTextBlock === null) {
currentTextBlock = block.text;
} else {
currentTextBlock += block.text;
}
} else {
// If we have accumulated text, flush it before adding non-text block
if (currentTextBlock !== null) {
merged.push({ type: "text", text: currentTextBlock });
currentTextBlock = null;
}
merged.push(block);
}
}

// Flush any remaining text
if (currentTextBlock !== null) {
merged.push({ type: "text", text: currentTextBlock });
}

return merged;
}

export const ErrorBlock = (props: {
data: ErrorNotificationEvent["data"];
onRetry?: () => void;
Expand Down Expand Up @@ -321,9 +361,14 @@ export const UserMessagesBlock = (props: { data: UserNotificationEvent[] }) => {
export const AgentMessagesBlock = (props: {
data: AgentNotificationEvent[];
}) => {
// Merge consecutive text chunks to prevent fragmented display
const mergedContent = mergeConsecutiveTextBlocks(
props.data.map((item) => item.content),
);

return (
<div className="flex flex-col gap-2">
<ContentBlocks data={props.data.map((item) => item.content)} />
<ContentBlocks data={mergedContent} />
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ const CachePanel = () => {
});
// Request updated cache info after purge
refetch();
} catch (err) {
} catch (error) {
toast({
title: "Error",
description:
err instanceof Error ? err.message : "Failed to purge cache",
error instanceof Error ? error.message : "Failed to purge cache",
variant: "danger",
});
} finally {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/editor/code/readonly-diff.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* Copyright 2024 Marimo. All rights reserved. */
import { unifiedMergeView } from "@codemirror/merge";
import { EditorView } from "@codemirror/view";
import CodeMirror from "@uiw/react-codemirror";
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ui/confirmation-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export const ConfirmationButton: React.FC<ConfirmationButtonProps> = ({

return (
<AlertDialog open={open} onOpenChange={setOpen}>
<AlertDialogTrigger asChild>{children}</AlertDialogTrigger>
<AlertDialogTrigger asChild={true}>{children}</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{title}</AlertDialogTitle>
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/core/ai/context/providers/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export class TableContextProvider extends AIContextProvider<TableContextItem> {

// Build shape information
const shape = [
num_rows != null ? `${num_rows} rows` : undefined,
num_columns != null ? `${num_columns} columns` : undefined,
num_rows == null ? undefined : `${num_rows} rows`,
num_columns == null ? undefined : `${num_columns} columns`,
]
.filter(Boolean)
.join(", ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { parseLatex } from "../embedded/latex";
import { languageMetadataField } from "../metadata";
import type { LanguageAdapter } from "../types";

export interface MarkdownLanguageAdapterMetadata extends MarkdownMetadata {}
export type MarkdownLanguageAdapterMetadata = MarkdownMetadata;

/**
* Language adapter for Markdown.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export class SQLLanguageAdapter
const metadata = result.metadata as SQLLanguageAdapterMetadata;

if (metadata.engine && metadata.engine !== DUCKDB_ENGINE) {
setLatestEngineSelected(metadata.engine as ConnectionName);
setLatestEngineSelected(metadata.engine);
}

return [result.code, result.offset, metadata];
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/core/codemirror/lsp/federated-lsp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class FederatedLanguageServerClient implements ILanguageServerClient {
params: LSP.PublishDiagnosticsParams;
}) => void,
): () => boolean {
const callbacks: Array<() => boolean> = [];
const callbacks: (() => boolean)[] = [];
for (const client of this.clients) {
callbacks.push(client.onNotification(listener));
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/core/vscode/is-in-vscode.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright 2025 Marimo. All rights reserved. */
/* Copyright 2024 Marimo. All rights reserved. */

/**
* Whether the current environment is in the VSCode extension
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/plugins/impl/plotly/parse-from-template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface PlotlyTemplateParser {
export function createParser(hovertemplate: string): PlotlyTemplateParser {
// Regular expression to match the pattern key=%{selector}
// Match any characters except = for the key (non-greedy to avoid capturing previous content)
const regex = /([^=<>]+)=%{([^}]+)}/g;
const regex = /([^<=>]+)=%{([^}]+)}/g;

// Create an object to hold the key-selector pairs
const keySelectorPairs: Record<string, string> = {};
Expand Down
26 changes: 13 additions & 13 deletions frontend/src/utils/__tests__/formatting.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,24 @@ describe("formatBytes", () => {
it("should format kilobytes", () => {
expect(formatBytes(1024, locale)).toBe("1 KB");
expect(formatBytes(1536, locale)).toBe("1.5 KB");
expect(formatBytes(10240, locale)).toBe("10 KB");
expect(formatBytes(10_240, locale)).toBe("10 KB");
});

it("should format megabytes", () => {
expect(formatBytes(1048576, locale)).toBe("1 MB"); // 1024^2
expect(formatBytes(1572864, locale)).toBe("1.5 MB"); // 1.5 * 1024^2
expect(formatBytes(10485760, locale)).toBe("10 MB");
expect(formatBytes(1_048_576, locale)).toBe("1 MB"); // 1024^2
expect(formatBytes(1_572_864, locale)).toBe("1.5 MB"); // 1.5 * 1024^2
expect(formatBytes(10_485_760, locale)).toBe("10 MB");
});

it("should format gigabytes", () => {
expect(formatBytes(1073741824, locale)).toBe("1 GB"); // 1024^3
expect(formatBytes(1610612736, locale)).toBe("1.5 GB"); // 1.5 * 1024^3
expect(formatBytes(10737418240, locale)).toBe("10 GB");
expect(formatBytes(1_073_741_824, locale)).toBe("1 GB"); // 1024^3
expect(formatBytes(1_610_612_736, locale)).toBe("1.5 GB"); // 1.5 * 1024^3
expect(formatBytes(10_737_418_240, locale)).toBe("10 GB");
});

it("should format terabytes", () => {
expect(formatBytes(1099511627776, locale)).toBe("1 TB"); // 1024^4
expect(formatBytes(1649267441664, locale)).toBe("1.5 TB"); // 1.5 * 1024^4
expect(formatBytes(1_099_511_627_776, locale)).toBe("1 TB"); // 1024^4
expect(formatBytes(1_649_267_441_664, locale)).toBe("1.5 TB"); // 1.5 * 1024^4
});

it("should respect locale parameter", () => {
Expand All @@ -55,9 +55,9 @@ describe("formatTime", () => {
});

it("should format microseconds", () => {
expect(formatTime(0.0000001, locale)).toBe("0.1µs");
expect(formatTime(0.0000005, locale)).toBe("0.5µs");
expect(formatTime(0.000000999, locale)).toBe("1µs"); // rounded by prettyNumber
expect(formatTime(0.000_000_1, locale)).toBe("0.1µs");
expect(formatTime(0.000_000_5, locale)).toBe("0.5µs");
expect(formatTime(0.000_000_999, locale)).toBe("1µs"); // rounded by prettyNumber
});

it("should format milliseconds", () => {
Expand Down Expand Up @@ -100,7 +100,7 @@ describe("formatTime", () => {
});

it("should handle edge cases", () => {
expect(formatTime(0.0009999, locale)).toBe("999.9µs");
expect(formatTime(0.000_999_9, locale)).toBe("999.9µs");
expect(formatTime(59.999, locale)).toBe("60s"); // rounded by prettyNumber
expect(formatTime(3599.999, locale)).toBe("59m 60s"); // rounded by prettyNumber
});
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/utils/numbers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ export const maxFractionalDigits = memoizeLastValue((locale: string) => {
maximumFractionDigits: option,
}).format(1);
return option;
} catch (e) {
Logger.error(e);
} catch (error) {
Logger.error(error);
}
}
return 0;
Expand Down
Loading