release: ship v1.5.0 with on-device writing suggestions
Adds next-sentence suggestions while typing, weekly input insights and a personal phrase memory to the desktop app, and fixes custom instructions so they process the text instead of inserting the instruction's own wording. Local model requests are now bounded and individually cancellable. Bumps the product version to 1.5.0 (Android/iOS build 1050000), refreshes the landing and web download links, and records the new INPUT feature rows and the open verification gaps in the infrastructure map.
This commit is contained in:
parent
99f06c253c
commit
5c11ee2fde
104 changed files with 14410 additions and 174 deletions
80
apps/desktop/tests/main/ipc/suggestion-handlers.test.ts
Normal file
80
apps/desktop/tests/main/ipc/suggestion-handlers.test.ts
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { IPC_CHANNELS } from '@d3ro/core/ipc-channels'
|
||||
|
||||
const handlers = vi.hoisted(
|
||||
() => new Map<string, (event: unknown, params: unknown) => Promise<unknown>>()
|
||||
)
|
||||
const eventHandlers = vi.hoisted(() => new Map<string, (...args: unknown[]) => void>())
|
||||
const configSet = vi.hoisted(() => vi.fn())
|
||||
const suggestion = vi.hoisted(() => ({
|
||||
setEnabled: vi.fn(),
|
||||
applyConfig: vi.fn(),
|
||||
dismiss: vi.fn(),
|
||||
getState: vi.fn(() => ({ enabled: true }))
|
||||
}))
|
||||
const hideSuggestionOverlay = vi.hoisted(() => vi.fn())
|
||||
|
||||
vi.mock('electron', () => ({
|
||||
ipcMain: {
|
||||
handle: vi.fn((channel: string, handler: (event: unknown, params: unknown) => Promise<unknown>) => {
|
||||
handlers.set(channel, handler)
|
||||
}),
|
||||
on: vi.fn((channel: string, handler: (...args: unknown[]) => void) => {
|
||||
eventHandlers.set(channel, handler)
|
||||
})
|
||||
}
|
||||
}))
|
||||
|
||||
vi.mock('../../../src/main/services/ConfigService', () => ({ configSet }))
|
||||
vi.mock('../../../src/main/services/SuggestionService', () => ({
|
||||
getSuggestionService: () => suggestion
|
||||
}))
|
||||
vi.mock('../../../src/main/windows/WindowManager', () => ({
|
||||
applySuggestionOverlayConfig: vi.fn(),
|
||||
hideSuggestionOverlay
|
||||
}))
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.resetModules()
|
||||
vi.clearAllMocks()
|
||||
handlers.clear()
|
||||
eventHandlers.clear()
|
||||
const mod = await import('../../../src/main/ipc/suggestion-handlers')
|
||||
mod.registerSuggestionHandlers()
|
||||
})
|
||||
|
||||
describe('SUGGESTION.SET_CONFIG', () => {
|
||||
it('명시적으로 활성화할 때 서비스의 warm-up 경로를 사용한다', async () => {
|
||||
const handler = handlers.get(IPC_CHANNELS.SUGGESTION.SET_CONFIG)
|
||||
if (!handler) throw new Error('suggestion config handler was not registered')
|
||||
|
||||
await handler({}, { enabled: true })
|
||||
|
||||
expect(suggestion.setEnabled).toHaveBeenCalledWith(true)
|
||||
expect(configSet).not.toHaveBeenCalledWith('suggestionEnabled', true)
|
||||
})
|
||||
|
||||
it('분당 요청 상한을 12로 강제한다', async () => {
|
||||
const handler = handlers.get(IPC_CHANNELS.SUGGESTION.SET_CONFIG)
|
||||
if (!handler) throw new Error('suggestion config handler was not registered')
|
||||
|
||||
await handler({}, { maxRequestsPerMinute: 99 })
|
||||
|
||||
expect(configSet).toHaveBeenCalledWith('suggestionMaxRequestsPerMinute', 12)
|
||||
})
|
||||
})
|
||||
|
||||
describe('POPUP_SUGGESTION.DISMISS', () => {
|
||||
it('서비스 이벤트를 기다리지 않고 창을 숨긴 뒤 제안을 취소한다', () => {
|
||||
const handler = eventHandlers.get(IPC_CHANNELS.POPUP_SUGGESTION.DISMISS)
|
||||
if (!handler) throw new Error('suggestion dismiss handler was not registered')
|
||||
|
||||
handler({})
|
||||
|
||||
expect(hideSuggestionOverlay).toHaveBeenCalledTimes(1)
|
||||
expect(suggestion.dismiss).toHaveBeenCalledWith('dismissed')
|
||||
expect(hideSuggestionOverlay.mock.invocationCallOrder[0]).toBeLessThan(
|
||||
suggestion.dismiss.mock.invocationCallOrder[0]
|
||||
)
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue