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
16 changes: 2 additions & 14 deletions apps/desktop/src/app/chat/sidebar/order.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,27 +111,15 @@ describe('orderRowsWithinGroups', () => {
it('reorders within a group without moving the dividers', () => {
const rows = [session('a'), session('b'), divider('yesterday'), session('c'), session('d')]

expect(ids(orderRowsWithinGroups(rows, ['b', 'a', 'd', 'c']))).toEqual([
'b',
'a',
'--yesterday--',
'd',
'c'
])
expect(ids(orderRowsWithinGroups(rows, ['b', 'a', 'd', 'c']))).toEqual(['b', 'a', '--yesterday--', 'd', 'c'])
})

it('never moves a row across a date divider', () => {
// 'd' is ranked first overall, but it lives below the divider and must
// stay there — chronology owns the groups, the drag only ranks inside one.
const rows = [session('a'), session('b'), divider('lastWeek'), session('c'), session('d')]

expect(ids(orderRowsWithinGroups(rows, ['d', 'c', 'b', 'a']))).toEqual([
'b',
'a',
'--lastWeek--',
'd',
'c'
])
expect(ids(orderRowsWithinGroups(rows, ['d', 'c', 'b', 'a']))).toEqual(['b', 'a', '--lastWeek--', 'd', 'c'])
})

it('leaves rows the order does not name in their recency slot', () => {
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src/app/chat/sidebar/sessions-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ export function SidebarSessionsSection({
// The flat recents/pinned list is the only place sessions reorder by hand;
// grouped/tree views always sort by creation date and never drag.
const sessionsDraggable = sortable && !!onReorderSessions

// Only Pinned arrives pre-ordered as a flat sequence. Recents keeps its
// recency sort — the drag order is layered on per date group below, so the
// buckets stay truthful and a reorder never costs the list its dividers.
Expand Down
7 changes: 2 additions & 5 deletions apps/desktop/src/components/assistant-ui/thread/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,7 @@ export function buildGroups(signature: string): MessageGroup[] {
// Walk turns newest-first, summing their render weights until the budget is met;
// everything before the first kept turn is hidden. `minVisible` turns are kept
// regardless of weight. Returns the index of that first visible group.
export function firstVisibleGroupIndex(
groups: readonly MessageGroup[],
budget: number,
minVisible = 0
): number {
export function firstVisibleGroupIndex(groups: readonly MessageGroup[], budget: number, minVisible = 0): number {
let firstVisible = groups.length

for (let i = groups.length - 1, weight = 0; i >= 0; i--) {
Expand Down Expand Up @@ -381,6 +377,7 @@ const ThreadMessageListInner: FC<ThreadMessageListProps> = ({
renderBudget,
renderBudget >= RENDER_BUDGET ? MIN_VISIBLE_GROUPS : 0
)

const visibleGroups = hiddenCount > 0 ? groups.slice(hiddenCount) : groups

// Where the always-rendered live tail begins. Derived from the WEIGHTED
Expand Down
4 changes: 1 addition & 3 deletions apps/desktop/src/components/chat/disclosure-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,7 @@ export function DisclosureRow({
{action}
</span>
)}
{trailing && (
<span className="flex h-(--conversation-line-height) shrink-0 items-center pl-1.5">{trailing}</span>
)}
{trailing && <span className="flex h-(--conversation-line-height) shrink-0 items-center pl-1.5">{trailing}</span>}
</div>
)
}
13 changes: 11 additions & 2 deletions apps/desktop/src/lib/render-weight.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,24 @@ describe('messagePaintWeight', () => {

it('prices an image card flat, however long its data URL', () => {
const card = (chars: number) => [
{ type: 'tool-call', toolName: 'image_generate', args: {}, result: { image: `data:image/png;base64,${'A'.repeat(chars)}` } }
{
type: 'tool-call',
toolName: 'image_generate',
args: {},
result: { image: `data:image/png;base64,${'A'.repeat(chars)}` }
}
]

expect(messagePaintWeight(card(10_000_000))).toBe(messagePaintWeight(card(80)))
})

it('charges nothing for a row that renders nothing', () => {
const hoisted = [
{ type: 'tool-call', toolName: 'todo', args: { todos: Array.from({ length: 40 }, (_, i) => ({ content: `t${i}` })) } },
{
type: 'tool-call',
toolName: 'todo',
args: { todos: Array.from({ length: 40 }, (_, i) => ({ content: `t${i}` })) }
},
{ type: 'tool-call', toolName: 'react_to_message', args: { emoji: '❤️' } }
]

Expand Down
Loading