round 3: disambiguate standalone compaction sections
This commit is contained in:
@@ -71,6 +71,7 @@ interface ToolCallTextParts {
|
|||||||
|
|
||||||
interface SelectedRequest {
|
interface SelectedRequest {
|
||||||
turn: number | null
|
turn: number | null
|
||||||
|
section: number
|
||||||
number: number
|
number: number
|
||||||
group: string
|
group: string
|
||||||
}
|
}
|
||||||
@@ -1453,6 +1454,7 @@ export function TrajectoryTable({
|
|||||||
? []
|
? []
|
||||||
: allRecords.filter(record =>
|
: allRecords.filter(record =>
|
||||||
record.turn === selectedRequest.turn
|
record.turn === selectedRequest.turn
|
||||||
|
&& record.section === selectedRequest.section
|
||||||
&& record.group === selectedRequest.group,
|
&& record.group === selectedRequest.group,
|
||||||
)
|
)
|
||||||
const selectedRequestAssistant = selectedRequestRecords.find(
|
const selectedRequestAssistant = selectedRequestRecords.find(
|
||||||
@@ -1505,6 +1507,7 @@ export function TrajectoryTable({
|
|||||||
selectedRequestInfo?.cumulativeUsage ?? selectedRequestUsage
|
selectedRequestInfo?.cumulativeUsage ?? selectedRequestUsage
|
||||||
const selectedRequestOptions = selectedRequestInfo?.requestConfig
|
const selectedRequestOptions = selectedRequestInfo?.requestConfig
|
||||||
const activeTurn = selectedRequest === null ? selected?.turn : selectedRequest.turn
|
const activeTurn = selectedRequest === null ? selected?.turn : selectedRequest.turn
|
||||||
|
const activeSection = selectedRequest === null ? selected?.section : selectedRequest.section
|
||||||
const selectedTabs = selectedRequest !== null
|
const selectedTabs = selectedRequest !== null
|
||||||
? REQUEST_TABS.filter(tab => tab.id !== 'options' || selectedRequestOptions !== undefined)
|
? REQUEST_TABS.filter(tab => tab.id !== 'options' || selectedRequestOptions !== undefined)
|
||||||
: selected === undefined ? [] : detailTabs(selected)
|
: selected === undefined ? [] : detailTabs(selected)
|
||||||
@@ -1520,6 +1523,7 @@ export function TrajectoryTable({
|
|||||||
selected !== undefined && selectedAssistantRequest !== undefined
|
selected !== undefined && selectedAssistantRequest !== undefined
|
||||||
? {
|
? {
|
||||||
turn: selected.turn,
|
turn: selected.turn,
|
||||||
|
section: selected.section,
|
||||||
number: selectedAssistantRequest,
|
number: selectedAssistantRequest,
|
||||||
group: selected.group,
|
group: selected.group,
|
||||||
}
|
}
|
||||||
@@ -1629,7 +1633,11 @@ export function TrajectoryTable({
|
|||||||
: `Request #${request}${requestInfo?.purpose === 'compaction' ? ' · Compaction' : ''}`
|
: `Request #${request}${requestInfo?.purpose === 'compaction' ? ' · Compaction' : ''}`
|
||||||
const requestSelected = request !== undefined
|
const requestSelected = request !== undefined
|
||||||
&& selectedRequest?.turn === record.turn
|
&& selectedRequest?.turn === record.turn
|
||||||
|
&& selectedRequest.section === record.section
|
||||||
&& selectedRequest.number === request
|
&& selectedRequest.number === request
|
||||||
|
const sectionActive = record.turn === null
|
||||||
|
? activeSection === record.section
|
||||||
|
: activeTurn === record.turn
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={`${record.cell.index}:${record.collapsedSummaryKind ?? 'record'}`}
|
key={`${record.cell.index}:${record.collapsedSummaryKind ?? 'record'}`}
|
||||||
@@ -1715,6 +1723,7 @@ export function TrajectoryTable({
|
|||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
selectRequest({
|
selectRequest({
|
||||||
turn: record.turn,
|
turn: record.turn,
|
||||||
|
section: record.section,
|
||||||
number: request,
|
number: request,
|
||||||
group: record.group,
|
group: record.group,
|
||||||
})
|
})
|
||||||
@@ -1734,7 +1743,7 @@ export function TrajectoryTable({
|
|||||||
&& !isRequestOnly
|
&& !isRequestOnly
|
||||||
&& record.turnStart && (
|
&& record.turnStart && (
|
||||||
<span
|
<span
|
||||||
className={activeTurn === record.turn
|
className={sectionActive
|
||||||
? `${css.turnLabel} ${css.turnLabelActive}`
|
? `${css.turnLabel} ${css.turnLabelActive}`
|
||||||
: css.turnLabel}
|
: css.turnLabel}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -312,6 +312,70 @@ describe('tab switching in ConversationRoot', () => {
|
|||||||
expect(view.container.textContent).not.toContain('Turn null')
|
expect(view.container.textContent).not.toContain('Turn null')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('activates only the selected standalone compaction section', async () => {
|
||||||
|
const nodes = [
|
||||||
|
{ kind: 'user', seq: 1, time: 1_000, content: [], source: null },
|
||||||
|
{
|
||||||
|
kind: 'assistant', seq: 2, time: 2_000, turn: 1, step: 1,
|
||||||
|
blocks: [{ kind: 'text', text: 'before first compaction' }],
|
||||||
|
},
|
||||||
|
{ kind: 'user', seq: 5, time: 5_000, content: [], source: null },
|
||||||
|
{
|
||||||
|
kind: 'assistant', seq: 6, time: 6_000, turn: 2, step: 1,
|
||||||
|
blocks: [{ kind: 'text', text: 'between compactions' }],
|
||||||
|
},
|
||||||
|
{ kind: 'user', seq: 9, time: 9_000, content: [], source: null },
|
||||||
|
{
|
||||||
|
kind: 'assistant', seq: 10, time: 10_000, turn: 3, step: 1,
|
||||||
|
blocks: [{ kind: 'text', text: 'after second compaction' }],
|
||||||
|
},
|
||||||
|
] as unknown as ConversationSnapshot['nodes']
|
||||||
|
const compactions: RequestView[] = [
|
||||||
|
{
|
||||||
|
purpose: 'compaction',
|
||||||
|
startSeq: 3,
|
||||||
|
turn: null,
|
||||||
|
step: 0,
|
||||||
|
startedAt: 3_000,
|
||||||
|
completedAt: 4_000,
|
||||||
|
status: 'complete',
|
||||||
|
summary: [{ type: 'text', text: 'first standalone summary' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
purpose: 'compaction',
|
||||||
|
startSeq: 7,
|
||||||
|
turn: null,
|
||||||
|
step: 0,
|
||||||
|
startedAt: 7_000,
|
||||||
|
completedAt: 8_000,
|
||||||
|
status: 'complete',
|
||||||
|
summary: [{ type: 'text', text: 'second standalone summary' }],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const b = await bench(historySnapshot(nodes, { requests: compactions }))
|
||||||
|
mount(b.slots, nodes)
|
||||||
|
fireEvent.click(screen.getByRole('tab', { name: 'Trajectory' }))
|
||||||
|
|
||||||
|
const firstRequest = screen.getByRole('button', { name: 'Request #2 · Compaction' })
|
||||||
|
const secondRequest = screen.getByRole('button', { name: 'Request #4 · Compaction' })
|
||||||
|
const firstSection = firstRequest.closest('tr')?.querySelector('span')
|
||||||
|
const secondSection = secondRequest.closest('tr')?.querySelector('span')
|
||||||
|
expect(firstSection?.textContent).toBe('Between turns')
|
||||||
|
expect(secondSection?.textContent).toBe('Between turns')
|
||||||
|
|
||||||
|
fireEvent.click(firstRequest)
|
||||||
|
expect(firstSection?.className).toMatch(/turnLabelActive/)
|
||||||
|
expect(secondSection?.className).not.toMatch(/turnLabelActive/)
|
||||||
|
expect(screen.getByText('Request #2')).toBeTruthy()
|
||||||
|
expect(screen.getByText('Compaction · Between turns')).toBeTruthy()
|
||||||
|
|
||||||
|
fireEvent.click(secondRequest)
|
||||||
|
expect(firstSection?.className).not.toMatch(/turnLabelActive/)
|
||||||
|
expect(secondSection?.className).toMatch(/turnLabelActive/)
|
||||||
|
expect(screen.getByText('Request #4')).toBeTruthy()
|
||||||
|
expect(screen.getByText('Compaction · Between turns')).toBeTruthy()
|
||||||
|
})
|
||||||
|
|
||||||
it('dragging the overview focuses overlapping records without filtering the ledger', async () => {
|
it('dragging the overview focuses overlapping records without filtering the ledger', async () => {
|
||||||
const b = await bench()
|
const b = await bench()
|
||||||
mount(b.slots)
|
mount(b.slots)
|
||||||
|
|||||||
Reference in New Issue
Block a user