fix(desktop): harden session, meeting, caption and LLM lifecycles; route LLM calls through the gateway
This commit is contained in:
parent
3a46437f28
commit
ddc78546f0
62 changed files with 4786 additions and 648 deletions
64
apps/desktop/tests/unit/renderer-models-redteam-r2-1.test.ts
Normal file
64
apps/desktop/tests/unit/renderer-models-redteam-r2-1.test.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// tests/unit/renderer-models-redteam-r2-1.test.ts
|
||||
// 렌더러 순수 모델:
|
||||
// - 녹음 화면 복원: main 사본과 먼저 도착한 이벤트를 id 로 합친다
|
||||
// - 회의 채팅 패널: main 이 기억하는 대화를 표시 메시지로 바꾼다(키 충돌 없음)
|
||||
// - 명령어 폼: 저장 거부 사유를 검증 메시지로 바꾼다(빈 프롬프트·길이 초과)
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { ErrorCode } from '@d3ro/core/errors'
|
||||
import { mergeRestoredItems } from '../../src/renderer/pages/meeting/live-restore'
|
||||
import { toPanelMessages, withRestoredHistory } from '../../src/renderer/components/meeting/meeting-chat-history'
|
||||
import { commandSaveError } from '../../src/renderer/pages/commands/command-form'
|
||||
|
||||
describe('mergeRestoredItems', () => {
|
||||
it('main 사본을 기준으로, 조회 중 먼저 온 항목은 중복 없이 합치고 시간 순으로 둔다', () => {
|
||||
const restored = [
|
||||
{ id: 'a', t: 1 },
|
||||
{ id: 'b', t: 2 },
|
||||
]
|
||||
const arrived = [
|
||||
{ id: 'b', t: 2 },
|
||||
{ id: 'c', t: 3 },
|
||||
]
|
||||
expect(mergeRestoredItems(restored, arrived, (x) => x.t).map((x) => x.id)).toEqual(['a', 'b', 'c'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('meeting chat history', () => {
|
||||
it('보관된 턴을 순서 번호 timestamp 로 바꿔 목록 키가 겹치지 않는다', () => {
|
||||
const messages = toPanelMessages([
|
||||
{ role: 'user', content: 'q1' },
|
||||
{ role: 'assistant', content: 'a1' },
|
||||
{ role: 'user', content: 'q2' },
|
||||
])
|
||||
const keys = messages.map((m) => `${m.role}-${m.timestamp}`)
|
||||
expect(new Set(keys).size).toBe(3)
|
||||
expect(messages.map((m) => m.content)).toEqual(['q1', 'a1', 'q2'])
|
||||
})
|
||||
|
||||
it('조회가 끝나기 전에 보낸 새 메시지는 지우지 않고 뒤에 둔다', () => {
|
||||
const merged = withRestoredHistory(
|
||||
[{ role: 'user', content: '새 질문', timestamp: 1_700_000_000_000 }],
|
||||
[{ role: 'user', content: '이전 질문' }, { role: 'assistant', content: '이전 답' }],
|
||||
)
|
||||
expect(merged.map((m) => m.content)).toEqual(['이전 질문', '이전 답', '새 질문'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('commandSaveError', () => {
|
||||
it('빈 프롬프트·길이 초과는 저장 전에 검증 메시지다', () => {
|
||||
expect(commandSaveError({ kind: 'draft', draft: { name: 'n', description: '', prompt: ' ' } })).toEqual({
|
||||
key: 'mobile.commands.syncError.validation',
|
||||
})
|
||||
expect(commandSaveError({ kind: 'draft', draft: { name: 'n'.repeat(81), description: '', prompt: 'p' } })).not.toBeNull()
|
||||
expect(commandSaveError({ kind: 'draft', draft: { name: 'n', description: '', prompt: 'p' } })).toBeNull()
|
||||
})
|
||||
|
||||
it('main 의 검증 거부는 검증 메시지, 그 밖의 실패는 호출자가 원문을 보여 준다(null)', () => {
|
||||
expect(
|
||||
commandSaveError({ kind: 'ipc', error: { code: ErrorCode.ConfigWriteFailed, message: 'Failed: Instruction prompt is too long (max 4000 characters)' } }),
|
||||
).not.toBeNull()
|
||||
expect(commandSaveError({ kind: 'ipc', error: { code: ErrorCode.ConfigInvalidValue, message: 'x' } })).not.toBeNull()
|
||||
expect(commandSaveError({ kind: 'ipc', error: { code: ErrorCode.ConfigWriteFailed, message: 'disk full' } })).toBeNull()
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue