fix(desktop): keep pre-compression transcript reachable after in-place /compress (#105256)
This commit is contained in:
@@ -776,6 +776,56 @@ describe('usePromptActions /compress', () => {
|
||||
expect(renderedText).toContain('sure, here is the summary')
|
||||
})
|
||||
|
||||
it('keeps pre-compression messages reachable after the transcript rewrite (#105256)', async () => {
|
||||
const seeds: Record<string, unknown>[] = []
|
||||
|
||||
const requestGateway = vi.fn(async (method: string, _params?: Record<string, unknown>, _timeoutMs?: number) => {
|
||||
if (method === 'session.compress') {
|
||||
return {
|
||||
removed: 2,
|
||||
summary: { headline: 'Compressed: 4 → 2 messages' },
|
||||
messages: [
|
||||
{ role: 'user', content: 'summarized context' },
|
||||
{ role: 'assistant', content: 'sure, here is the summary' }
|
||||
]
|
||||
} as never
|
||||
}
|
||||
|
||||
return {} as never
|
||||
})
|
||||
|
||||
let handle: HarnessHandle | null = null
|
||||
await actRender(
|
||||
<Harness
|
||||
onReady={h => (handle = h)}
|
||||
onSeedState={s => seeds.push(s)}
|
||||
refreshSessions={async () => undefined}
|
||||
requestGateway={requestGateway}
|
||||
seedMessages={[
|
||||
{ id: 'pre-1', role: 'user', parts: [textPart('pre-compression user turn')], timestamp: 0 },
|
||||
{ id: 'pre-2', role: 'assistant', parts: [textPart('pre-compression assistant reply')], timestamp: 1 }
|
||||
]}
|
||||
/>
|
||||
)
|
||||
|
||||
await handle!.submitText('/compress')
|
||||
|
||||
// The transcript was replaced with the post-compress history.
|
||||
const finalMessages = seeds[seeds.length - 1]?.messages as Array<{ parts?: Array<{ text?: string }> }>
|
||||
|
||||
const renderedText = (finalMessages ?? [])
|
||||
.flatMap(message => (message.parts ?? []).map(part => part.text ?? ''))
|
||||
.join('\n')
|
||||
|
||||
expect(renderedText).toContain('summarized context')
|
||||
expect(renderedText).toContain('sure, here is the summary')
|
||||
// Active-session scrollback: the pre-compression segment stays in the
|
||||
// transcript so scrolling up still reaches it.
|
||||
expect(renderedText).toContain('pre-compression user turn')
|
||||
expect(renderedText).toContain('pre-compression assistant reply')
|
||||
expect(renderedText.indexOf('pre-compression user turn')).toBeLessThan(renderedText.indexOf('summarized context'))
|
||||
})
|
||||
|
||||
it('uses the compute-host response transcript and success output', async () => {
|
||||
const seeds: Record<string, unknown>[] = []
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ import { skillInvocationText } from '@hermes/shared'
|
||||
import { parseCommandDispatch, parseSlashCommand } from '@hermes/shared'
|
||||
import { type MutableRefObject, useCallback, useRef } from 'react'
|
||||
|
||||
import { mergeOlderTranscriptPage } from '@/app/chat/transcript-backfill'
|
||||
import { prepareDefaultNewSession } from '@/app/session/new-session-route'
|
||||
import { invalidateContextBreakdown } from '@/app/shell/hooks/use-context-breakdown'
|
||||
import { getProfiles } from '@/hermes'
|
||||
@@ -763,10 +764,18 @@ export function useSlashCommand(deps: SlashCommandDeps) {
|
||||
// toChatMessages handles it directly. updateSessionState only
|
||||
// publishes for the active runtime, guarding against a late result
|
||||
// clobbering the foreground after a session switch.
|
||||
// The pre-compression segment stays reachable in the active
|
||||
// session (#105256): the rewrite shares no anchor with the live
|
||||
// transcript, so grafting would drop everything before the
|
||||
// summary. Prepend it instead (deduped by row/message id), keeping
|
||||
// the post-compress history authoritative for overlapping rows.
|
||||
if (Array.isArray(result?.messages)) {
|
||||
updateSessionState(
|
||||
sessionId,
|
||||
state => ({ ...state, messages: toChatMessages(result.messages!) }),
|
||||
state => ({
|
||||
...state,
|
||||
messages: mergeOlderTranscriptPage(toChatMessages(result.messages!), state.messages)
|
||||
}),
|
||||
storedSessionId
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user