release 1.0.1: fix resume showing a blank transcript
A resumed session loaded its wire messages but never rebuilt the on-screen history, so -r/-c and /resume rendered a blank transcript. Convert the stored messages back into transcript lines and seed the panel with them at mount and after /resume.
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { expect, test } from 'bun:test';
|
||||
import { historyFromMessages } from '../src/ui/transcript';
|
||||
import type { Line } from '../src/ui/transcript';
|
||||
|
||||
const kind = (lines: Line[]) => lines.map((l) => l.kind);
|
||||
|
||||
test('historyFromMessages maps a saved conversation into transcript lines', () => {
|
||||
const lines = historyFromMessages([
|
||||
{ role: 'user', content: 'fix the pagination test' },
|
||||
{ role: 'assistant', content: 'Looking at the suite' },
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{ type: 'text', text: 'Found it.' },
|
||||
{
|
||||
type: 'tool-call',
|
||||
toolCallId: 't1',
|
||||
toolName: 'edit_file',
|
||||
input: { path: 'test/PageTest.php', oldString: 'a', newString: 'b' },
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
role: 'tool',
|
||||
content: [{ type: 'tool-result', toolCallId: 't1', toolName: 'edit_file', output: { type: 'text', value: 'Replaced 1 occurrence' } }],
|
||||
},
|
||||
]);
|
||||
|
||||
// user + assistant text + assistant text part + tool call + existing call line
|
||||
expect(kind(lines)).toEqual(['user', 'assistant', 'assistant', 'tool']);
|
||||
const tool = lines.at(-1)!;
|
||||
expect(tool.kind).toBe('tool');
|
||||
if (tool.kind === 'tool') {
|
||||
expect(tool.result).toBe('Replaced 1 occurrence');
|
||||
expect(tool.ok).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
test('historyFromMessages unwraps SDK-wrapped and json-wrapped tool outputs', () => {
|
||||
const lines = historyFromMessages([
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [{ type: 'tool-call', toolCallId: 'g1', toolName: 'grep', input: { pattern: 'TODO' } }],
|
||||
},
|
||||
{
|
||||
role: 'tool',
|
||||
content: [{ type: 'tool-result', toolCallId: 'g1', toolName: 'grep', output: { type: 'text', value: 'src/a.ts:1: TODO' } }],
|
||||
},
|
||||
]);
|
||||
const line = lines[0]!;
|
||||
expect(line.kind).toBe('tool');
|
||||
if (line.kind === 'tool') expect(line.result).toBe('1 hit');
|
||||
});
|
||||
|
||||
test('historyFromMessages marks a tool-error call as failed', () => {
|
||||
const lines = historyFromMessages([
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [{ type: 'tool-call', toolCallId: 'b1', toolName: 'bash', input: { command: 'false' } }],
|
||||
},
|
||||
{
|
||||
role: 'tool',
|
||||
content: [{ type: 'tool-error', toolCallId: 'b1', toolName: 'bash', output: { type: 'text', value: 'exit 1' } }],
|
||||
},
|
||||
]);
|
||||
const line = lines[0]!;
|
||||
expect(line.kind).toBe('tool');
|
||||
if (line.kind === 'tool') {
|
||||
expect(line.ok).toBe(false);
|
||||
expect(line.result).toBe('exit 1');
|
||||
}
|
||||
});
|
||||
|
||||
test('historyFromMessages drops a tool result with no matching call (pruned lead-in)', () => {
|
||||
const lines = historyFromMessages([
|
||||
{ role: 'user', content: 'continue' },
|
||||
{
|
||||
role: 'tool',
|
||||
content: [{ type: 'tool-result', toolCallId: 'gone', toolName: 'grep', output: { type: 'text', value: 'x' } }],
|
||||
},
|
||||
]);
|
||||
// Only the user line remains; the orphaned result is not floated.
|
||||
expect(kind(lines)).toEqual(['user']);
|
||||
});
|
||||
|
||||
test('historyFromMessages skips system and empty messages', () => {
|
||||
const lines = historyFromMessages([
|
||||
{ role: 'system', content: 'You are an agent.' },
|
||||
{ role: 'user', content: '' },
|
||||
{ role: 'assistant', content: 'ok' },
|
||||
]);
|
||||
expect(kind(lines)).toEqual(['assistant']);
|
||||
});
|
||||
Reference in New Issue
Block a user