* feat: persist AI conversations and add chat history Store transcripts and attachment previews in IndexedDB, separate conversation history from transport lifetime, and add document-aware switching with shared Storybook coverage. Preserve interrupted activity and guard stale writes and async switches. * test: group chat history tests by domain * feat: simplify chat history navigation and diagnostics Use a compact header with searchable document-scoped history and a correctly anchored conversation menu. Move diagnostic copying into the menu with copy-result feedback, and separate Storybook fixtures from composition. * fix: address chat history review findings * test: cover harness shutdown and restored chat scrolling * fix: preserve Portless proxy port in MCP routes * docs: clarify UI animation conventions * feat: configure reasoning display and animate disclosure * fix: separate transcript following from reasoning disclosure * fix: restore selected chat after document recovery * refactor: separate chat history persistence and sessions * style: format reasoning story imports
46 lines
1.6 KiB
TypeScript
46 lines
1.6 KiB
TypeScript
import type { Page } from '@playwright/test'
|
|
|
|
/** Hold reasoning open until the test explicitly completes the turn. */
|
|
export async function installReasoningTransport(page: Page): Promise<void> {
|
|
await page.evaluate(() => {
|
|
window.openPencil?.setChatTransport(() => ({
|
|
async sendMessages() {
|
|
return new ReadableStream({
|
|
start(controller) {
|
|
controller.enqueue({ type: 'start', messageId: crypto.randomUUID() })
|
|
controller.enqueue({ type: 'reasoning-start', id: 'thinking' })
|
|
controller.enqueue({
|
|
type: 'reasoning-delta',
|
|
id: 'thinking',
|
|
delta: 'Inspecting the selected layout.'
|
|
})
|
|
window.addEventListener(
|
|
'finish-test-reasoning',
|
|
() => {
|
|
controller.enqueue({ type: 'reasoning-end', id: 'thinking' })
|
|
controller.enqueue({ type: 'text-start', id: 'answer' })
|
|
controller.enqueue({
|
|
type: 'text-delta',
|
|
id: 'answer',
|
|
delta: 'Finished inspecting the layout.'
|
|
})
|
|
controller.enqueue({ type: 'text-end', id: 'answer' })
|
|
controller.enqueue({ type: 'finish', finishReason: 'stop' })
|
|
controller.close()
|
|
},
|
|
{ once: true }
|
|
)
|
|
}
|
|
})
|
|
},
|
|
async reconnectToStream() {
|
|
return null
|
|
}
|
|
}))
|
|
})
|
|
}
|
|
|
|
export async function finishReasoning(page: Page): Promise<void> {
|
|
await page.evaluate(() => window.dispatchEvent(new Event('finish-test-reasoning')))
|
|
}
|