Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 0 additions & 1 deletion src/McpResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,6 @@ Call ${handleDialog.name} to handle it before continuing.`);
return response;
}

response.push(`## Console Message ${data.consoleMessageStableId}`);
response.push(formatConsoleEventVerbose(data));
return response;
}
Expand Down
73 changes: 29 additions & 44 deletions src/formatters/consoleFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,64 +6,49 @@

import type {ConsoleMessageData} from '../McpResponse.js';

const logLevels: Record<string, string> = {
log: 'Log',
info: 'Info',
warning: 'Warning',
error: 'Error',
exception: 'Exception',
assert: 'Assert',
};

// The short format for a console message, based on a previous format.
export function formatConsoleEventShort(msg: ConsoleMessageData): string {
const args = msg.args ? formatArgs(msg, false) : '';
return `msgid=${msg.consoleMessageStableId} [${msg.type}] ${msg.message}${args}`;
return `msgid=${msg.consoleMessageStableId} [${msg.type}] ${msg.message} (${msg.args?.length ?? 0} args)`;
}

// The verbose format for a console message, including all details.
export function formatConsoleEventVerbose(msg: ConsoleMessageData): string {
const logLevel = msg.type ? (logLevels[msg.type] ?? 'Log') : 'Log';
let result = `${logLevel}> ${msg.message}`;
function getArgs(msg: ConsoleMessageData) {
const args = [...(msg.args ?? [])];

if (msg.args && msg.args.length > 0) {
result += formatArgs(msg, true);
// If there is no text, the first argument serves as text (see formatMessage).
if (!msg.message) {
args.shift();
}

result += `
ID: ${msg.consoleMessageStableId}`;
result += `
Type: ${msg.type}`;
return args;
}

// The verbose format for a console message, including all details.
export function formatConsoleEventVerbose(msg: ConsoleMessageData): string {
const result = [
`ID: ${msg.consoleMessageStableId}`,
`Message: ${msg.type}> ${msg.message}`,
formatArgs(msg),
];

return result.join('\n');
}

return result;
function formatArg(arg: unknown) {
return typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
}

// If `includeAllArgs` is false, only includes the first arg and indicates that there are more args.
function formatArgs(
consoleData: ConsoleMessageData,
includeAllArgs = false,
): string {
if (!consoleData.args || consoleData.args.length === 0) {
function formatArgs(consoleData: ConsoleMessageData): string {
const args = getArgs(consoleData);

if (!args.length) {
return '';
}

let formattedArgs = '';
// In the short format version, we only include the first arg.
const messageArgsToFormat = includeAllArgs
? consoleData.args
: [consoleData.args[0]];

for (const arg of messageArgsToFormat) {
if (arg !== consoleData.message) {
formattedArgs += ' ';
formattedArgs +=
typeof arg === 'object' ? JSON.stringify(arg) : String(arg);
}
}
const result = ['### Arguments'];

if (!includeAllArgs && consoleData.args.length > 1) {
formattedArgs += ` ...`;
for (const [key, arg] of args.entries()) {
result.push(`Arg #${key}: ${formatArg(arg)}`);
}

return formattedArgs.length > 0 ? ` Args:${formattedArgs}` : '';
return result.join('\n');
}
38 changes: 38 additions & 0 deletions tests/formatters/consoleFormatter.test.js.snapshot
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
exports[`consoleFormatter > formatConsoleEventShort > formats a console.log message 1`] = `
msgid=1 [log] Hello, world! (0 args)
`;

exports[`consoleFormatter > formatConsoleEventShort > formats a console.log message with multiple arguments 1`] = `
msgid=3 [log] Processing file: (2 args)
`;

exports[`consoleFormatter > formatConsoleEventShort > formats a console.log message with one argument 1`] = `
msgid=2 [log] Processing file: (1 args)
`;

exports[`consoleFormatter > formatConsoleEventVerbose > formats a console.error message 1`] = `
ID: 4
Message: error> Something went wrong

`;

exports[`consoleFormatter > formatConsoleEventVerbose > formats a console.log message 1`] = `
ID: 1
Message: log> Hello, world!

`;

exports[`consoleFormatter > formatConsoleEventVerbose > formats a console.log message with multiple arguments 1`] = `
ID: 3
Message: log> Processing file:
### Arguments
Arg #0: file.txt
Arg #1: another file
`;

exports[`consoleFormatter > formatConsoleEventVerbose > formats a console.log message with one argument 1`] = `
ID: 2
Message: log> Processing file:
### Arguments
Arg #0: file.txt
`;
78 changes: 15 additions & 63 deletions tests/formatters/consoleFormatter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* SPDX-License-Identifier: Apache-2.0
*/

import assert from 'node:assert';
import {describe, it} from 'node:test';

import {
Expand All @@ -13,131 +12,84 @@ import {
} from '../../src/formatters/consoleFormatter.js';
import type {ConsoleMessageData} from '../../src/McpResponse.js';

describe('consoleFormatter', () => {
describe.only('consoleFormatter', () => {
describe('formatConsoleEventShort', () => {
it('formats a console.log message', () => {
it('formats a console.log message', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 1,
type: 'log',
message: 'Hello, world!',
args: [],
};
const result = formatConsoleEventShort(message);
assert.equal(result, 'msgid=1 [log] Hello, world!');
t.assert.snapshot?.(result);
});

it('formats a console.log message with one argument', () => {
it('formats a console.log message with one argument', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 2,
type: 'log',
message: 'Processing file:',
args: ['file.txt'],
};
const result = formatConsoleEventShort(message);
assert.equal(result, 'msgid=2 [log] Processing file: Args: file.txt');
t.assert.snapshot?.(result);
});

it('formats a console.log message with multiple arguments', () => {
it('formats a console.log message with multiple arguments', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 3,
type: 'log',
message: 'Processing file:',
args: ['file.txt', 'another file'],
};
const result = formatConsoleEventShort(message);
assert.equal(result, 'msgid=3 [log] Processing file: Args: file.txt ...');
});

it('does not include args if message is the same as arg', () => {
const message: ConsoleMessageData = {
consoleMessageStableId: 4,
type: 'log',
message: 'Hello',
args: ['Hello'],
};
const result = formatConsoleEventShort(message);
assert.equal(result, 'msgid=4 [log] Hello');
t.assert.snapshot?.(result);
});
});

describe('formatConsoleEventVerbose', () => {
it('formats a console.log message', () => {
it('formats a console.log message', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 1,
type: 'log',
message: 'Hello, world!',
args: [],
};
const result = formatConsoleEventVerbose(message);
assert.equal(
result,
`Log> Hello, world!
ID: 1
Type: log`,
);
t.assert.snapshot?.(result);
});

it('formats a console.log message with one argument', () => {
it('formats a console.log message with one argument', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 2,
type: 'log',
message: 'Processing file:',
args: ['file.txt'],
};
const result = formatConsoleEventVerbose(message);
assert.equal(
result,
`Log> Processing file: Args: file.txt
ID: 2
Type: log`,
);
t.assert.snapshot?.(result);
});

it('formats a console.log message with multiple arguments', () => {
it('formats a console.log message with multiple arguments', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 3,
type: 'log',
message: 'Processing file:',
args: ['file.txt', 'another file'],
};
const result = formatConsoleEventVerbose(message);
assert.equal(
result,
`Log> Processing file: Args: file.txt another file
ID: 3
Type: log`,
);
t.assert.snapshot?.(result);
});

it('formats a console.error message', () => {
it('formats a console.error message', t => {
const message: ConsoleMessageData = {
consoleMessageStableId: 4,
type: 'error',
message: 'Something went wrong',
};
const result = formatConsoleEventVerbose(message);
assert.equal(
result,
`Error> Something went wrong
ID: 4
Type: error`,
);
});

it('does not include args if message is the same as arg', () => {
const message: ConsoleMessageData = {
consoleMessageStableId: 5,
type: 'log',
message: 'Hello',
args: ['Hello', 'World'],
};
const result = formatConsoleEventVerbose(message);
assert.equal(
result,
`Log> Hello Args: World
ID: 5
Type: log`,
);
t.assert.snapshot?.(result);
});
});
});
4 changes: 0 additions & 4 deletions tests/tools/console.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ describe('console', () => {

const formattedResponse = response.format('test', context);
const textContent = formattedResponse[0] as {text: string};
assert.ok(
textContent.text.includes('## Console Message 1'),
'Should contain console message title',
);
assert.ok(
textContent.text.includes('msgid=1 [error] This is an error'),
'Should contain console message body',
Expand Down