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
2 changes: 2 additions & 0 deletions src/main/utils/jsonl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,8 @@ export async function analyzeSessionFileMetadata(

if (
!firstUserMessage &&
// teammate relays (and system output/interruptions) must not become the preview
isParsedUserChunkMessage(parsed) &&
entry.type === 'user' &&
!('isMeta' in entry && entry.isMeta === true)
) {
Expand Down
65 changes: 65 additions & 0 deletions test/main/utils/jsonl.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,71 @@ describe('jsonl', () => {
}
});

it('skips teammate relays when picking firstUserMessage', async () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'jsonl-relay-'));
try {
const filePath = path.join(tempDir, 'session.jsonl');
const relay =
'<teammate-message teammate_id="a">hello</teammate-message>\nWhy is this tag in the log?';
const lines = [
JSON.stringify({
type: 'user',
uuid: 'u1',
timestamp: '2026-01-01T00:00:00.000Z',
message: { role: 'user', content: relay },
isMeta: false,
}),
];
fs.writeFileSync(filePath, `${lines.join('\n')}\n`, 'utf8');

const result = await analyzeSessionFileMetadata(filePath);

expect(result.firstUserMessage).toBeNull();
} finally {
try {
fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
} catch {
// Best-effort cleanup; ignore ENOTEMPTY on Windows when dir is in use
}
}
});

it('picks a later real user message when the session opens with a relay', async () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'jsonl-relay2-'));
try {
const filePath = path.join(tempDir, 'session.jsonl');
const relay =
'<teammate-message teammate_id="a">hello</teammate-message>\nWhy is this tag in the log?';
const lines = [
JSON.stringify({
type: 'user',
uuid: 'u1',
timestamp: '2026-01-01T00:00:00.000Z',
message: { role: 'user', content: relay },
isMeta: false,
}),
JSON.stringify({
type: 'user',
uuid: 'u2',
timestamp: '2026-01-01T00:00:05.000Z',
message: { role: 'user', content: 'the actual user question' },
isMeta: false,
}),
];
fs.writeFileSync(filePath, `${lines.join('\n')}\n`, 'utf8');

const result = await analyzeSessionFileMetadata(filePath);

expect(result.firstUserMessage?.text).toBe('the actual user question');
} finally {
try {
fs.rmSync(tempDir, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });
} catch {
// Best-effort cleanup; ignore ENOTEMPTY on Windows when dir is in use
}
}
});

it('sums total spend across all assistant usage in one pass', async () => {
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'jsonl-spend-'));
try {
Expand Down
Loading