Skip to content

Commit e0fa7ae

Browse files
committed
feat: group identical consecutive console messages in list_console_messages
Group consecutive messages with the same type and text, displaying a count suffix (e.g. [20 times]) similar to Chrome DevTools' console grouping behavior. Grouping is applied before pagination so the grouped count accurately reflects the total items. - Add groupConsecutive() static method to ConsoleFormatter - Add toStringGrouped()/toJSONGrouped() for count-aware formatting - Add optional count field to ConsoleMessageConcise interface - Apply grouping in McpResponse before pagination Fixes #904
1 parent b53752d commit e0fa7ae

2 files changed

Lines changed: 62 additions & 5 deletions

File tree

src/McpResponse.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,17 +1031,25 @@ Call ${handleDialog.name} to handle it before continuing.`);
10311031

10321032
response.push('## Console messages');
10331033
if (messages.length) {
1034+
const grouped = ConsoleFormatter.groupConsecutive(messages);
10341035
const paginationData = this.#dataWithPagination(
1035-
messages,
1036+
grouped,
10361037
this.#consoleDataOptions.pagination,
10371038
);
10381039
structuredContent.pagination = paginationData.pagination;
10391040
response.push(...paginationData.info);
10401041
response.push(
1041-
...paginationData.items.map(message => message.toString()),
1042+
...paginationData.items.map(({message, count}) =>
1043+
message instanceof ConsoleFormatter
1044+
? message.toStringGrouped(count)
1045+
: message.toString(),
1046+
),
10421047
);
1043-
structuredContent.consoleMessages = paginationData.items.map(message =>
1044-
message.toJSON(),
1048+
structuredContent.consoleMessages = paginationData.items.map(
1049+
({message, count}) =>
1050+
message instanceof ConsoleFormatter
1051+
? message.toJSONGrouped(count)
1052+
: message.toJSON(),
10451053
);
10461054
} else {
10471055
response.push('<no console messages found>');

src/formatters/ConsoleFormatter.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import {UncaughtError} from '../PageCollector.js';
1313
import * as DevTools from '../third_party/index.js';
1414
import type {ConsoleMessage} from '../third_party/index.js';
1515

16+
import type {IssueFormatter} from './IssueFormatter.js';
17+
1618
export interface ConsoleFormatterOptions {
1719
fetchDetailedData?: boolean;
1820
id: number;
@@ -32,6 +34,7 @@ interface ConsoleMessageConcise {
3234
text: string;
3335
argsCount: number;
3436
id: number;
37+
count?: number;
3538
}
3639

3740
interface ConsoleMessageDetailed extends ConsoleMessageConcise {
@@ -175,6 +178,15 @@ export class ConsoleFormatter {
175178
return convertConsoleMessageConciseToString(this.toJSON());
176179
}
177180

181+
// The short format with a repeat count.
182+
toStringGrouped(count: number): string {
183+
const json = this.toJSON();
184+
if (count > 1) {
185+
json.count = count;
186+
}
187+
return convertConsoleMessageConciseToString(json);
188+
}
189+
178190
// The verbose format for a console message, including all details.
179191
toStringDetailed(): string {
180192
return convertConsoleMessageConciseDetailedToString(this.toJSONDetailed());
@@ -201,6 +213,42 @@ export class ConsoleFormatter {
201213
};
202214
}
203215

216+
toJSONGrouped(count: number): ConsoleMessageConcise {
217+
const json = this.toJSON();
218+
if (count > 1) {
219+
json.count = count;
220+
}
221+
return json;
222+
}
223+
224+
/**
225+
* Groups consecutive messages with the same type and text.
226+
* Similar to Chrome DevTools' console grouping behavior.
227+
*/
228+
static groupConsecutive(
229+
messages: Array<ConsoleFormatter | IssueFormatter>,
230+
): Array<{message: ConsoleFormatter | IssueFormatter; count: number}> {
231+
const grouped: Array<{
232+
message: ConsoleFormatter | IssueFormatter;
233+
count: number;
234+
}> = [];
235+
for (const msg of messages) {
236+
const prev = grouped[grouped.length - 1];
237+
if (
238+
prev &&
239+
prev.message instanceof ConsoleFormatter &&
240+
msg instanceof ConsoleFormatter &&
241+
prev.message.#type === msg.#type &&
242+
prev.message.#text === msg.#text
243+
) {
244+
prev.count++;
245+
} else {
246+
grouped.push({message: msg, count: 1});
247+
}
248+
}
249+
return grouped;
250+
}
251+
204252
toJSONDetailed(): ConsoleMessageDetailed {
205253
return {
206254
id: this.#id,
@@ -216,7 +264,8 @@ export class ConsoleFormatter {
216264
}
217265

218266
function convertConsoleMessageConciseToString(msg: ConsoleMessageConcise) {
219-
return `msgid=${msg.id} [${msg.type}] ${msg.text} (${msg.argsCount} args)`;
267+
const countSuffix = msg.count && msg.count > 1 ? ` [${msg.count} times]` : '';
268+
return `msgid=${msg.id} [${msg.type}] ${msg.text} (${msg.argsCount} args)${countSuffix}`;
220269
}
221270

222271
function convertConsoleMessageConciseDetailedToString(

0 commit comments

Comments
 (0)