Files
makelore/tests/unit/chat-transcript.test.ts
inman 80e8386fa6
Some checks failed
Electron E2E / Electron E2E (macos-latest) (push) Has been cancelled
Electron E2E / Electron E2E (ubuntu-latest) (push) Has been cancelled
Electron E2E / Electron E2E (windows-latest) (push) Has been cancelled
feat: update Makelore modules and conversations
2026-07-31 10:08:41 +08:00

904 lines
33 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, expect, it } from 'vitest';
import {
formatVisibleChatTranscript,
getToolVisibilityId,
} from '@/pages/Chat/chat-transcript';
import { mergeChatCommandCatalog } from '@/pages/Chat/chat-command-registry';
import type { RawMessage } from '@/types/chat';
const messages: RawMessage[] = [
{
id: 'user-1',
role: 'user',
timestamp: Date.UTC(2026, 6, 18, 8, 0, 0),
content: [
{ type: 'text', text: 'Inspect the attachment.' },
{ type: 'image', mimeType: 'image/png', data: 'VERY_SECRET_BASE64' },
],
_attachedFiles: [
{
fileName: 'diagram.png',
mimeType: 'image/png',
fileSize: 10,
preview: 'data:image/png;base64,ALSO_SECRET',
filePath: 'C:\\Users\\alice\\secret\\diagram.png',
runtimeUrl: 'http://127.0.0.1:43123/api/files?path=C%3A%5CUsers%5Calice%5Csecret%5Cdiagram.png',
},
],
},
{
id: 'assistant-1',
role: 'assistant',
content: [
{ type: 'thinking', thinking: 'Private chain fragment' },
{
type: 'tool_use',
id: 'tool-1',
name: 'read',
input: {
path: '/Users/alice/private/notes.txt',
screenshot: 'data:image/png;base64,TOOL_SECRET',
rawBytes: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
},
},
{ type: 'text', text: 'Finished.' },
],
},
];
describe('formatVisibleChatTranscript', () => {
it('writes binary placeholders and never emits data, base64, loopback URLs, or absolute paths', () => {
const markdown = formatVisibleChatTranscript(messages, {
showThinking: true,
showTimestamps: true,
expandedToolIds: new Set([getToolVisibilityId('assistant-1', 'tool-1', 0)]),
});
expect(markdown).toContain('[Attached image/png: diagram.png]');
expect(markdown).toContain('[Attached image/png: attachment]');
expect(markdown).toContain('Private chain fragment');
expect(markdown).toContain('Tool: read');
expect(markdown).toContain('[Local path: notes.txt]');
expect(markdown).not.toMatch(/VERY_SECRET|ALSO_SECRET|TOOL_SECRET|A{64}|base64/i);
expect(markdown).not.toMatch(/127\.0\.0\.1|C:\\Users|\/Users\/alice/);
});
it('omits thinking and collapsed tool details while retaining visible answers and tool names', () => {
const markdown = formatVisibleChatTranscript(messages, {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('Inspect the attachment.');
expect(markdown).toContain('Finished.');
expect(markdown).toContain('Tool: read');
expect(markdown).not.toContain('Private chain fragment');
expect(markdown).not.toContain('notes.txt');
expect(markdown).not.toContain('2026-07-18');
});
it('defaults the explicit answer-only mode to user messages and the final answer', () => {
const markdown = formatVisibleChatTranscript(messages, {
showThinking: true,
showTimestamps: false,
includeExecution: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('Inspect the attachment.');
expect(markdown).toContain('Finished.');
expect(markdown).not.toContain('Private chain fragment');
expect(markdown).not.toContain('Tool: read');
});
it('redacts alternate binary encodings, file URLs, IPv6 loopback, and additional absolute roots', () => {
const base64Url = `${'a'.repeat(32)}-${'b'.repeat(32)}_${'c'.repeat(8)}`;
const wrappedBase64 = `${'A'.repeat(40)}\n${'B'.repeat(40)}`;
const markdown = formatVisibleChatTranscript([{
id: 'assistant-safety',
role: 'assistant',
content: [{
type: 'tool_use',
id: 'tool-safety',
name: 'inspect',
input: {
dataUrl: `data:image/png;charset=utf-8;name=secret.png;base64,${wrappedBase64}`,
base64Url,
ipv6Loopback: 'http://[::1]:43123/private/file.png',
fileUrl: 'file:///Users/alice/private/file.txt',
hostedFileUrl: 'file://localhost/Users/alice/private/hosted.txt',
remoteHostedFileUrl: 'file://server/share/remote-hosted.txt',
rootPath: '/root/.ssh/id_ed25519',
usrPath: '/usr/local/share/private.txt',
srvPath: '/srv/internal/secret.txt',
customPath: '/company/internal/private/roadmap.txt',
rootFile: '/secret.txt',
forwardWindowsPath: 'C:/secret.txt',
windowsPath: 'C:\\Users\\alice\\private\\windows.txt',
spacedWindowsPath: 'C:\\Users\\Alice\\Private Notes\\secret.txt',
uncPath: '\\\\fileserver\\private\\unc.txt',
},
}],
}], {
showThinking: true,
showTimestamps: true,
expandedToolIds: new Set([
getToolVisibilityId('assistant-safety', 'tool-safety', 0),
]),
});
expect(markdown).toContain('[Binary data omitted]');
expect(markdown).toContain('[Local path: file.txt]');
expect(markdown).toContain('[Local path: id_ed25519]');
expect(markdown).not.toContain(base64Url);
expect(markdown).not.toContain('A'.repeat(40));
expect(markdown).not.toContain('B'.repeat(40));
expect(markdown).not.toMatch(
/data:image|base64|http:\/\/\[::1\]|file:\/\/|\/root\/|\/usr\/|\/srv\/|\/company\/|\/secret\.txt|Private Notes/i,
);
expect(markdown).not.toMatch(/C:[/\\]|\\\\fileserver/);
});
it('preserves an extensionless slash token because it may be a dynamic project command', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [
'/single',
'/review.v2',
'Use /base64 now',
'[the guide](/docs/getting-started)',
'Call /api/v1/users',
].join('\n'),
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toMatch(/\n\/single\n/);
expect(markdown).toContain('/review.v2');
expect(markdown).toContain('Use /base64 now');
expect(markdown).toContain('[the guide](/docs/getting-started)');
expect(markdown).toContain('Call /api/v1/users');
});
it('preserves common root-relative routes without merging adjacent paths', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [
'GET /v1/users now',
'Load /assets/js/app.js and /health/check',
'Paths /Volumes/Private/file.txt and /data/private/cache.bin',
].join('\n'),
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('GET /v1/users now');
expect(markdown).toContain('Load /assets/js/app.js and /health/check');
expect(markdown).toContain(
'Paths [Local path: file.txt] and [Local path: cache.bin]',
);
});
it('does not exempt an absolute local path merely because it is a Markdown link', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [
'See [guide](/docs/getting-started).',
'See [secret](/Users/alice/private/secret.txt).',
'See [volume](/Volumes/Private/volume.txt).',
].join('\n'),
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('See [guide](/docs/getting-started).');
expect(markdown).toContain('See [secret]([Local path: secret.txt]).');
expect(markdown).toContain('See [volume]([Local path: volume.txt]).');
expect(markdown).not.toMatch(/\/Users\/alice|\/Volumes\/Private/);
});
it('preserves a known nested project command while sanitizing path arguments', () => {
const commandCatalog = mergeChatCommandCatalog([{
name: 'workspace/build',
hints: ['$ARGUMENTS'],
}]);
const slashCommandNames = new Set(commandCatalog.flatMap(
(command) => [command.inputName, ...command.aliases],
));
const markdown = formatVisibleChatTranscript([{
role: 'user',
content: '/workspace/build inspect /Users/alice/private/input.txt',
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
slashCommandNames,
});
expect(markdown).toContain('/workspace/build inspect');
expect(markdown).toContain('[Local path: input.txt]');
expect(markdown).not.toContain('/Users/alice/private');
});
it('redacts forward-slash UNC paths and backtick-wrapped custom-root paths', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: '//server/share/private.txt\nGenerated at `/company/internal/secret.txt`',
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('[Local path: private.txt]');
expect(markdown).toContain('`[Local path: secret.txt]`');
expect(markdown).not.toMatch(/\/\/server\/share|\/company\/internal/);
});
it('redacts encoded and non-base64 data URLs, shorthand loopback, and spaced POSIX paths', () => {
const oversizedDataHeader = 'a'.repeat(2_050);
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [
'data:;base64,U0VDUkVUX1BBWUxPQUQ=',
'data:;base64,U0VD UkVU',
'data:image/png;base64,%2FSECRET_PAYLOAD_12345%3D',
'data:text/plain,PLAIN_TEXT_SECRET',
'data:text/plain;name="foo bar";base64,U0VDUkVU',
'data:foo,HEADER_FOO_SECRET',
'data:text,HEADER_TEXT_SECRET',
'data:@,HEADER_SYMBOL_SECRET',
'metadata:text/plain,hello',
'The data: are stored, safely.',
'data:image/png;base64,U0VDUkVU Done safely.',
`data:text/plain;name=${oversizedDataHeader},HEADER_LIMIT_SECRET`,
'data:text/plain;name="foo,QUOTE_SECRET',
'http://127.1:43123/private/file.png',
'http://localhost.:43123/private/dotted.png',
'Open `/Users/Alice/Private Notes/secret.txt` safely.',
'Use /copy now',
'/copy',
].join('\n'),
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('[Binary data omitted]');
expect(markdown).toContain('[Runtime attachment: file.png]');
expect(markdown).toContain('[Runtime attachment: dotted.png]');
expect(markdown).toContain('Open `[Local path: secret.txt]` safely.');
expect(markdown).toContain('Use /copy now');
expect(markdown).toMatch(/\n\/copy\n/);
expect(markdown).not.toMatch(
/127\.1|localhost\.|\/Users\/Alice|Private Notes\/secret\.txt/i,
);
expect(markdown).not.toMatch(/(^|\n)data:/im);
expect(markdown).not.toContain('U0VDUkVUX1BBWUxPQUQ=');
expect(markdown).not.toMatch(/U0VD|UkVU/);
expect(markdown).not.toContain('%2FSECRET_PAYLOAD_12345%3D');
expect(markdown).not.toContain('PLAIN_TEXT_SECRET');
expect(markdown).toContain('metadata:text/plain,hello');
expect(markdown).not.toMatch(
/HEADER_FOO_SECRET|HEADER_TEXT_SECRET|HEADER_SYMBOL_SECRET|are stored, safely/,
);
expect(markdown).toContain('[Binary data omitted] Done safely.');
expect(markdown).not.toMatch(/HEADER_LIMIT_SECRET|QUOTE_SECRET/);
});
it('redacts complete quoted data and loopback URL payloads with legal delimiters', () => {
const markdown = formatVisibleChatTranscript([{
id: 'assistant-delimited-urls',
role: 'assistant',
content: [{
type: 'tool_use',
id: 'tool-delimited-urls',
name: 'inspect',
input: {
parenthesized: 'data:text/plain,HEAD_SECRET)TAIL_SECRET',
apostrophe: 'data:text/plain,ONE_SECRET\'TWO_SECRET',
backtick: 'data:text/plain,LEFT_SECRET`RIGHT_SECRET',
spaced: 'data:text/plain,SEC RET',
loopbackParen:
'http://127.0.0.1:43123/private)TOP_SECRET_DIR/public.png',
loopbackApostrophe:
'http://localhost:43123/private\'SECOND_SECRET_DIR/public.png',
loopbackQuote:
'http://localhost:43123/private"HTTP_SECRET_DIR/public.png',
fileParen:
'file:///Users/alice/private)FILE_PAREN_SECRET/public.txt',
fileQuote:
'file:///Users/alice/private"FILE_SECRET_DIR/public.txt',
},
}],
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set([
getToolVisibilityId(
'assistant-delimited-urls',
'tool-delimited-urls',
0,
),
]),
});
expect(markdown).toContain('[Binary data omitted]');
expect(markdown).toContain('[Runtime attachment: public.png]');
expect(markdown).toContain('[Local path: public.txt]');
expect(markdown).not.toMatch(
/HEAD_SECRET|TAIL_SECRET|ONE_SECRET|TWO_SECRET|LEFT_SECRET|RIGHT_SECRET|SEC RET|TOP_SECRET_DIR|SECOND_SECRET_DIR|HTTP_SECRET_DIR|FILE_PAREN_SECRET|FILE_SECRET_DIR/,
);
});
it('redacts malformed data headers and direct unquoted local URL suffixes', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [
'data: text/plain,LEADING_SPACE_SECRET',
'data:\ttext/plain,TAB_HEADER_SECRET',
'data:\ftext/plain,FORM_FEED_HEADER_SECRET',
'data:text/\nplain,NEWLINE_HEADER_SECRET',
'data:text/plain;name=foo`bar,HEADER_BACKTICK_SECRET',
'data:text/plain;name=foo\\,BACKSLASH_COMMA_SECRET',
'da\nta:text/plain,DATA_SCHEME_SECRET',
'ht\ntp://localhost:43123/private/HTTP_SCHEME_SECRET/public.png',
'fi\nle:///Users/Alice/private/FILE_SCHEME_SECRET/public.txt',
'http://127.0.0.1:43123/private)TOP_SECRET_DIR/public.png',
'file:///Users/alice/private)FILE_SECRET_DIR/public.txt',
'http://local\nhost:43123/private/NEWLINE_LOOP_SECRET/public.png',
'file:///Users/ali\nce/private/NEWLINE_FILE_SECRET/public.txt',
'http://localhost:43123/private/\nHTTP_FINAL_FOLD_SECRET.png',
'file:///Users/Alice/private/\r\nFILE_FINAL_FOLD_SECRET.txt',
'`http://localhost:43123/private/\nHTTP_WRAPPED_FOLD_SECRET.png`',
'`file:///Users/Alice/private/\nFILE_WRAPPED_FOLD_SECRET.txt`',
'http://localhost:43123/Private Notes/HTTP_SPACE_SECRET/public.png',
'file:///Users/Alice/Private Notes/FILE_SPACE_SECRET/public.txt',
].join('\n'),
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('[Runtime attachment: public.png]');
expect(markdown).toContain('[Local path: public.txt]');
expect(markdown).toContain(
'[Runtime attachment: HTTP_FINAL_FOLD_SECRET.png]',
);
expect(markdown).toContain('[Local path: FILE_FINAL_FOLD_SECRET.txt]');
expect(markdown).toContain(
'`[Runtime attachment: HTTP_WRAPPED_FOLD_SECRET.png]`',
);
expect(markdown).toContain(
'`[Local path: FILE_WRAPPED_FOLD_SECRET.txt]`',
);
expect(markdown).not.toMatch(/private\/\r?\n(?:HTTP|FILE)_(?:FINAL|WRAPPED)_FOLD_SECRET/);
expect(markdown).not.toMatch(
/LEADING_SPACE_SECRET|TAB_HEADER_SECRET|FORM_FEED_HEADER_SECRET|NEWLINE_HEADER_SECRET|HEADER_BACKTICK_SECRET|BACKSLASH_COMMA_SECRET|DATA_SCHEME_SECRET|HTTP_SCHEME_SECRET|FILE_SCHEME_SECRET|TOP_SECRET_DIR|FILE_SECRET_DIR|NEWLINE_LOOP_SECRET|NEWLINE_FILE_SECRET|HTTP_SPACE_SECRET|FILE_SPACE_SECRET/,
);
});
it('stops a quoted data URL at its closing wrapper', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: 'Open "data:text/plain,secret" and then "click Save".',
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain(
'Open "[Binary data omitted]" and then "click Save".',
);
expect(markdown).not.toContain('secret');
});
it.each(['\n', '\r\n'])(
'stops an unclosed quoted data URL at the current line for %j',
(lineBreak) => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: `Open "data:text/plain,secret${lineBreak}Keep this visible.`,
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('Open "[Binary data omitted]');
expect(markdown).toContain('Keep this visible.');
expect(markdown).not.toContain('secret');
},
);
it.each([
['"', '\n'],
['"', '\r\n'],
['\'', '\n'],
['\'', '\r\n'],
['`', '\n'],
['`', '\r\n'],
])(
'does not consume visible text after a line-ended Data URL (%s, %j)',
(wrapper, lineBreak) => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content:
`Open ${wrapper}data:text/plain,FIRST_SECRET${lineBreak}`
+ `Keep this visible ${wrapper}quoted text${wrapper}.`,
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain(`Open ${wrapper}[Binary data omitted]`);
expect(markdown).toContain(
`Keep this visible ${wrapper}quoted text${wrapper}.`,
);
expect(markdown).not.toContain('FIRST_SECRET');
},
);
it.each([
['http://localhost:43123/private/', '[Runtime attachment: private]', '', '\n'],
['http://localhost:43123/private/', '[Runtime attachment: private]', '"', '\r\n'],
['file:///Users/Alice/private/', '[Local path: private]', '', '\n'],
['file:///Users/Alice/private/', '[Local path: private]', '`', '\r\n'],
])(
'does not fold ordinary prose into a line-ended local URL (%s, %s, %j)',
(url, placeholder, wrapper, lineBreak) => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content:
`Open ${wrapper}${url}${lineBreak}`
+ `Keep this visible.${wrapper}`,
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain(`Open ${wrapper}${placeholder}`);
expect(markdown).toContain(`Keep this visible.${wrapper}`);
},
);
it('preserves surrounding Markdown and prose when redacting Windows and file URL paths', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [
'Open `C:\\Users\\alice\\secret\\file.txt` and retry.',
'See `file:///Users/Alice/Private Notes/file.txt` safely.',
'See file:///Users/alice/private/file.txt and retry.',
'Open /Users/alice/file.txt and retry.',
'Open /Users/Alice/Private Notes/direct-posix.txt safely.',
'Open /Volumes/Private/volume.txt safely.',
'Open /data/private/cache.bin safely.',
'Open /company/internal/roadmap.txt safely.',
'Open /acme/Private Notes/acme.txt safely.',
'Open /project/My Folder/project.txt safely.',
'Open /Custom Root/private/custom.txt safely.',
'Open C:\\Users\\alice\\file.txt and retry.',
'Open C:\\Users\\Alice\\Private Notes\\direct-windows.txt safely.',
'Open C:/Users/alice/file.txt and retry.',
'Open C:/Users/Alice/Private Notes/direct-forward.txt safely.',
'Open \\\\server\\share\\file.txt and retry.',
].join('\n'),
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('Open `[Local path: file.txt]` and retry.');
expect(markdown).toContain('See `[Local path: file.txt]` safely.');
expect(markdown).toContain('See [Local path: file.txt] and retry.');
expect(markdown.match(/Open \[Local path: file\.txt\] and retry\./g))
.toHaveLength(4);
expect(markdown).toContain('Open [Local path: direct-posix.txt] safely.');
expect(markdown).toContain('Open [Local path: direct-windows.txt] safely.');
expect(markdown).toContain('Open [Local path: direct-forward.txt] safely.');
expect(markdown).toContain('Open [Local path: volume.txt] safely.');
expect(markdown).toContain('Open [Local path: cache.bin] safely.');
expect(markdown).toContain('Open [Local path: roadmap.txt] safely.');
expect(markdown).toContain('Open [Local path: acme.txt] safely.');
expect(markdown).toContain('Open [Local path: project.txt] safely.');
expect(markdown).toContain('Open [Local path: custom.txt] safely.');
expect(markdown).not.toMatch(
/Private Notes|My Folder|Custom Root|\/Volumes\/|\/data\/private|\/company\/internal/,
);
});
it('redacts a short Base64 payload in visible prose without changing the command token', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [
'Image base64=U0VDUkVU',
'Wrapped base64: `U0VDUkVU`',
'Spaced base64: U0VD UkVU',
'Folded base64: U0VD\nUkVU',
'CRLF base64: U0VD\r\nUkVU',
'Triple folded base64: QUJD\nREVG\nR0hJ',
'The data: analysis is complete.',
'Screenshot: attached below.',
'Preview: available tomorrow.',
'Use /base64 now',
].join('\n'),
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('Image base64=[Binary data omitted]');
expect(markdown).toContain('Wrapped base64: `[Binary data omitted]`');
expect(markdown).toContain('Spaced base64: [Binary data omitted]');
expect(markdown).toContain('Folded base64: [Binary data omitted]');
expect(markdown).toContain('CRLF base64: [Binary data omitted]');
expect(markdown).toContain('Triple folded base64: [Binary data omitted]');
expect(markdown).toContain('The data: analysis is complete.');
expect(markdown).toContain('Screenshot: attached below.');
expect(markdown).toContain('Preview: available tomorrow.');
expect(markdown).toContain('Use /base64 now');
expect(markdown).not.toContain('U0VDUkVU');
});
it('keeps multiple local paths on one line as separate placeholders', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [
'Paths C:\\Users\\Alice\\one.txt and C:\\data\\two.txt done',
'Paths C:/Users/Alice/one.txt and C:/data/two.txt done',
'Paths \\\\server\\share\\one.txt and \\\\server\\share\\two.txt done',
'Paths //server/share/one.txt and //server/share/two.txt done',
].join('\n'),
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown.match(/\[Local path: one\.txt\]/g)).toHaveLength(4);
expect(markdown.match(/\[Local path: two\.txt\]/g)).toHaveLength(4);
expect(markdown.match(/ and /g)).toHaveLength(4);
expect(markdown).not.toMatch(/C:[/\\]|\/\/server|\\\\server/);
});
it('stops spaced paths and URLs at punctuation or a following absolute value', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [
'POSIX /Volumes/one.txt, /data/two.txt done',
'POSIX /Volumes/one.txt; /data/two.txt done',
'POSIX /Volumes/one.txt /data/two.txt done',
'POSIX /Volumes/one.txt然后 /data/two.txt done',
'POSIX /Users/Alice/Private Notes/one.txt. Next /data/two.txt done',
'WIN C:\\Users\\A\\one.txt, C:\\Users\\B\\two.txt done',
'URL http://localhost:43123/Private Notes/one.png, http://localhost:43123/Private Notes/two.png done',
'URL file:///Users/Alice/Private Notes/one.txt; file:///Users/Alice/Private Notes/two.txt done',
].join('\n'),
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown.match(/\[Local path: one\.txt\]/g)).toHaveLength(7);
expect(markdown.match(/\[Local path: two\.txt\]/g)).toHaveLength(7);
expect(markdown.match(/\[Runtime attachment: one\.png\]/g)).toHaveLength(1);
expect(markdown.match(/\[Runtime attachment: two\.png\]/g)).toHaveLength(1);
expect(markdown).toContain(
'[Local path: one.txt]. Next [Local path: two.txt] done',
);
expect(markdown).not.toMatch(
/\/Volumes\/|\/data\/|\/Users\/|C:\\|localhost:43123|Private Notes/,
);
});
it('keeps punctuation inside one directory while redacting its full path', () => {
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [
'Open /Users/Alice/Smith, John/POSIX_COMMA_SECRET.txt safely.',
'Open C:\\Users\\Alice\\Smith, John\\WIN_COMMA_SECRET.txt safely.',
'Open C:/Users/Alice/R&D/WIN_AMP_SECRET.txt safely.',
'Open file:///Users/Alice/Smith, John/FILE_COMMA_SECRET.txt safely.',
'Open http://localhost:43123/Smith, John/HTTP_COMMA_SECRET.png safely.',
].join('\n'),
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('[Local path: POSIX_COMMA_SECRET.txt]');
expect(markdown).toContain('[Local path: WIN_COMMA_SECRET.txt]');
expect(markdown).toContain('[Local path: WIN_AMP_SECRET.txt]');
expect(markdown).toContain('[Local path: FILE_COMMA_SECRET.txt]');
expect(markdown).toContain('[Runtime attachment: HTTP_COMMA_SECRET.png]');
expect(markdown).not.toMatch(/Smith, John|R&D|\/Users\/|C:[/\\]|localhost/);
});
it('bounds punctuation-heavy path scanning for long visible messages', () => {
const startedAt = performance.now();
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: `Open /Custom Root/${'a,'.repeat(100_000)}tail/file.txt safely.`,
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
const elapsedMilliseconds = performance.now() - startedAt;
expect(markdown).toContain('[Local path: file.txt]');
expect(elapsedMilliseconds).toBeLessThan(1_500);
});
it.each([
['circular', (() => {
const value: Record<string, unknown> = {};
value.self = value;
return value;
})()],
['BigInt', { value: 1n }],
['throwing toJSON', { toJSON: () => { throw new Error('secret serializer failure'); } }],
])('uses a fixed placeholder when %s tool input cannot be serialized', (_label, input) => {
const markdown = formatVisibleChatTranscript([{
id: 'assistant-unserializable',
role: 'assistant',
content: [{
type: 'tool_use',
id: 'tool-unserializable',
name: 'inspect',
input,
}],
}], {
showThinking: true,
showTimestamps: false,
expandedToolIds: new Set([
getToolVisibilityId('assistant-unserializable', 'tool-unserializable', 0),
]),
});
expect(markdown).toContain('[Tool details unavailable]');
});
it('redacts short Base64 under explicit binary tool keys', () => {
const shortBase64 = 'U0VDUkVU';
const markdown = formatVisibleChatTranscript([{
id: 'assistant-short-binary',
role: 'assistant',
content: [{
type: 'tool_use',
id: 'tool-short-binary',
name: 'inspect',
input: {
screenshotBase64: shortBase64,
rawBytes: shortBase64,
label: 'ordinary short text',
},
}],
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set([
getToolVisibilityId('assistant-short-binary', 'tool-short-binary', 0),
]),
});
expect(markdown).not.toContain(shortBase64);
expect(markdown.match(/\[Binary data omitted\]/g)).toHaveLength(2);
expect(markdown).toContain('ordinary short text');
});
it('redacts short Base64 from JSON-encoded string tool input', () => {
const shortBase64 = 'U0VDUkVU';
const markdown = formatVisibleChatTranscript([{
id: 'assistant-string-binary',
role: 'assistant',
content: [{
type: 'tool_use',
id: 'tool-string-binary',
name: 'inspect',
input: JSON.stringify({
screenshotBase64: shortBase64,
ordinary: 'visible text',
}),
}],
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set([
getToolVisibilityId(
'assistant-string-binary',
'tool-string-binary',
0,
),
]),
});
expect(markdown).not.toContain(shortBase64);
expect(markdown).toContain('[Binary data omitted]');
expect(markdown).toContain('visible text');
});
it.each([
['plain labelled input', 'screenshotBase64: U0VDUkVU'],
['partial JSON input', '{"screenshotBase64":"U0VDUkVU"'],
['folded partial JSON input', '{"screenshotBase64":"U0VD\\nUkVU"'],
])('redacts short Base64 from %s', (_label, input) => {
const markdown = formatVisibleChatTranscript([{
id: 'assistant-partial-binary',
role: 'assistant',
content: [{
type: 'tool_use',
id: 'tool-partial-binary',
name: 'inspect',
input,
}],
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set([
getToolVisibilityId(
'assistant-partial-binary',
'tool-partial-binary',
0,
),
]),
});
expect(markdown).not.toContain('U0VDUkVU');
expect(markdown).toContain('[Binary data omitted]');
});
it('redacts single-segment absolute paths in structured tool details', () => {
const markdown = formatVisibleChatTranscript([{
id: 'assistant-structured-paths',
role: 'assistant',
content: [{
type: 'tool_use',
id: 'tool-structured-paths',
name: 'inspect',
input: {
dotEnv: '/.env',
extensionlessPath: '/secret',
},
}],
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set([
getToolVisibilityId(
'assistant-structured-paths',
'tool-structured-paths',
0,
),
]),
});
expect(markdown).toContain('[Local path: .env]');
expect(markdown).toContain('[Local path: secret]');
expect(markdown).not.toMatch(/"\/(?:\.env|secret)"/);
});
it('keeps every unnamed binary placeholder and deduplicates only a matching named attachment', () => {
const markdown = formatVisibleChatTranscript([{
id: 'user-binary',
role: 'user',
content: [
{ type: 'image', mimeType: 'image/png', data: 'FIRST' },
{ type: 'image', mimeType: 'image/png', data: 'SECOND' },
{ type: 'image', mimeType: 'image/png', data: 'THIRD', fileName: '/tmp/diagram.png' },
],
_attachedFiles: [{
fileName: 'diagram.png',
mimeType: 'image/png',
fileSize: 10,
preview: null,
}],
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown.match(/\[Attached image\/png: attachment\]/g)).toHaveLength(2);
expect(markdown.match(/\[Attached image\/png: diagram\.png\]/g)).toHaveLength(1);
});
it('sanitizes untrusted attachment names and MIME metadata before formatting placeholders', () => {
const encodedSecret = 'A'.repeat(80);
const shortDataUrlSecret = 'SHORT_SECRET_PAYLOAD_12345';
const fileUrlToken = 'TOP_SECRET_TOKEN';
const markdown = formatVisibleChatTranscript([{
id: 'user-attachment-metadata',
role: 'user',
content: [{
type: 'image',
mimeType: `data:image/png;base64,${encodedSecret}`,
data: 'BINARY',
fileName: encodedSecret,
}],
_attachedFiles: [
{
fileName: encodedSecret,
mimeType: 'image/png',
fileSize: 10,
preview: null,
},
{
fileName: 'safe.png',
mimeType: `data:image/png;base64,${encodedSecret}`,
fileSize: 10,
preview: null,
},
{
fileName: `data:image/png;base64,${shortDataUrlSecret}`,
mimeType: 'image/png',
fileSize: 10,
preview: null,
},
{
fileName: 'http://127.0.0.1:43123/api/files?path=C%3A%5CUsers%5CAlice%5Cprivate%5Csecret.png',
mimeType: 'image/png',
fileSize: 10,
preview: null,
},
{
fileName: `file://server/share/private.txt?token=${fileUrlToken}`,
mimeType: 'image/png',
fileSize: 10,
preview: null,
},
],
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set(),
});
expect(markdown).toContain('[Attached image/png: [Binary data omitted]]');
expect(markdown).toContain('[Attached application/octet-stream: safe.png]');
expect(markdown).not.toContain(encodedSecret);
expect(markdown).not.toContain(shortDataUrlSecret);
expect(markdown).not.toContain(fileUrlToken);
expect(markdown).not.toMatch(/127\.0\.0\.1|%5CUsers|file:\/\/server/i);
expect(markdown).not.toMatch(/data:image|base64/i);
});
it('uses stable fallbacks for empty message and tool IDs', () => {
expect(getToolVisibilityId('', '', 3)).toBe('message:tool:3');
const markdown = formatVisibleChatTranscript([{
role: 'assistant',
content: [{
type: 'tool_use',
id: '',
name: 'read',
input: { file: 'README.md' },
}],
}], {
showThinking: false,
showTimestamps: false,
expandedToolIds: new Set([
getToolVisibilityId('assistant-0', undefined, 0),
]),
});
expect(markdown).toContain('README.md');
});
});