feat: improve streaming and startup responsiveness

This commit is contained in:
mesalogo
2026-08-15 18:06:03 +08:00
parent ed8d1791b1
commit f27dd37f42
13 changed files with 1795 additions and 885 deletions
+64 -48
View File
@@ -82,6 +82,7 @@ import {
type DeepSeekHarnessFork
} from './agent/deepseek-harness-utility-launcher'
import { buildControlledHarnessEnvironment } from './agent/process-environment'
import { runStartupPrerequisites } from './startup-prerequisites'
const shortcut = 'CommandOrControl+Shift+Space'
const mainModuleDirectory = dirname(fileURLToPath(import.meta.url))
@@ -380,9 +381,11 @@ if (hasSingleInstanceLock) {
join(app.getPath('userData'), 'runtime-settings.json'),
secureCipher
)
const initialRuntimeSettings =
await settingsStore.getPublicSettings()
const initialSettings = await settingsStore.getResolvedSettings()
const [initialRuntimeSettings, initialResolvedSettings] =
await Promise.all([
settingsStore.getPublicSettings(),
settingsStore.getResolvedSettings()
])
globalTlsPolicy = new GlobalTlsPolicy(app)
globalTlsPolicy.install()
const capabilityService = new CapabilityService(
@@ -444,10 +447,6 @@ if (hasSingleInstanceLock) {
app.getPath('userData'),
'deepseek-harness'
)
await mkdir(deepSeekHarnessHome, {
recursive: true,
mode: 0o700
})
const launchDeepSeekHarness =
createDeepSeekHarnessUtilityLauncher({
bundledHostPath: bundledRuntimePaths.deepseekHarness,
@@ -458,56 +457,29 @@ if (hasSingleInstanceLock) {
fork: forkDeepSeekHarness,
terminateProcess: terminateHarnessUtilityProcess
})
knowledgeService = new KnowledgeService({
const startupKnowledgeService = new KnowledgeService({
databasePath: join(app.getPath('userData'), 'knowledge.sqlite'),
managedRoot: join(app.getPath('userData'), 'knowledge'),
extractStructured: createModelGraphExtractor(settingsStore),
parseDocument: documentParsingService.parse
})
await knowledgeService.initialize()
const knowledgeRuntimeSettings =
await settingsStore.getResolvedSettings()
void knowledgeService
.setEmbeddingProvider(
createEmbeddingProvider(knowledgeRuntimeSettings)
)
.catch(() => undefined)
void knowledgeService
.setRerankProvider(
createRerankProvider(knowledgeRuntimeSettings)
)
.catch(() => undefined)
assistantDatabase = new AssistantDatabase(
knowledgeService = startupKnowledgeService
const startupAssistantDatabase = new AssistantDatabase(
join(app.getPath('userData'), 'assistant.sqlite')
)
assistantDatabase.initialize(defaultWorkspace)
assistantDatabase.ensureChannelProjects(
defaultWorkspace,
initialRuntimeSettings.defaultModelProfileId
)
channelSettingsStore.reportRuntimeSelectionRepairs(
assistantDatabase.repairConversationRuntimeSelections(
initialRuntimeSettings
)
)
assistantDatabase = startupAssistantDatabase
const goodbuddyConfigService = new GoodBuddyConfigService(
applicationSettingsStore,
capabilityService
)
knowledgeGateway = new KnowledgeMcpGateway(knowledgeService, {
magicNotesDatabase: assistantDatabase,
configService: goodbuddyConfigService
})
await knowledgeGateway.start()
const subagentService = new SubagentService(
createDefaultModelRuntime(defaultWorkspace, initialSettings),
assistantDatabase,
undefined,
createSubagentProfileRuntimes(
defaultWorkspace,
initialSettings
)
const startupKnowledgeGateway = new KnowledgeMcpGateway(
startupKnowledgeService,
{
magicNotesDatabase: startupAssistantDatabase,
configService: goodbuddyConfigService
}
)
knowledgeGateway = startupKnowledgeGateway
const createRuntimeWithCapabilities = async (
settings: ResolvedRuntimeSettings,
target: SelectedRuntimeTarget
@@ -547,7 +519,7 @@ if (hasSingleInstanceLock) {
browserCapability?.enabled && browserCapability.supported
? browserService
: undefined,
knowledgeGateway,
knowledgeGateway: startupKnowledgeGateway,
webSearchEnabled: webSearchCapability?.enabled
})
}
@@ -576,9 +548,53 @@ if (hasSingleInstanceLock) {
resolved.target
)
}
runtime = new AgentRuntimeController(
await createConfiguredRuntime()
const configuredRuntime = await runStartupPrerequisites({
prepareDeepSeekHome: async () => {
await mkdir(deepSeekHarnessHome, {
recursive: true,
mode: 0o700
})
},
initializeKnowledgeAndGateway: async () => {
await startupKnowledgeService.initialize()
await Promise.all([
startupKnowledgeService.setEmbeddingProvider(
createEmbeddingProvider(initialResolvedSettings)
).catch(() => undefined),
startupKnowledgeService.setRerankProvider(
createRerankProvider(initialResolvedSettings)
).catch(() => undefined)
])
await startupKnowledgeGateway.start()
},
hydrateConfiguredRuntime: () =>
createConfiguredRuntime(initialResolvedSettings),
initializeAssistant: () => {
startupAssistantDatabase.initialize(defaultWorkspace)
startupAssistantDatabase.ensureChannelProjects(
defaultWorkspace,
initialRuntimeSettings.defaultModelProfileId
)
channelSettingsStore.reportRuntimeSelectionRepairs(
startupAssistantDatabase.repairConversationRuntimeSelections(
initialRuntimeSettings
)
)
}
})
const subagentService = new SubagentService(
createDefaultModelRuntime(
defaultWorkspace,
initialResolvedSettings
),
startupAssistantDatabase,
undefined,
createSubagentProfileRuntimes(
defaultWorkspace,
initialResolvedSettings
)
)
runtime = new AgentRuntimeController(configuredRuntime)
selectedRuntimeManager = new SelectedRuntimeManager(
createSelectedRuntime
)
@@ -120,6 +120,69 @@ describe('KnowledgeDatabase', () => {
.toHaveLength(1)
})
it('repairs a mismatched user version without losing current-schema data', async () => {
const { database, path } = await createDatabase()
const knowledgeBase = database.createKnowledgeBase({
name: 'Mismatch repair',
storageMode: 'reference'
})
seedDocument(database, knowledgeBase.id, 'mismatch-repair')
database.close()
const mismatch = new DatabaseSync(path)
mismatch.exec('PRAGMA user_version = 10')
mismatch.close()
const repaired = new KnowledgeDatabase(path)
openDatabases.push(repaired)
repaired.initialize()
expect(repaired.getKnowledgeBase(knowledgeBase.id)).toMatchObject({
name: 'Mismatch repair'
})
expect(repaired.listDocuments(knowledgeBase.id)).toHaveLength(1)
const inspection = new DatabaseSync(path)
expect(inspection.prepare('PRAGMA user_version').get()).toEqual({
user_version: 11
})
inspection.close()
})
it.each([
['migration version', 'INSERT INTO schema_migrations VALUES (12, ?)', true],
['user version', 'PRAGMA user_version = 12', false]
])('rejects a future %s without downgrading it', async (
_label,
statement,
hasParameter
) => {
const { database, path } = await createDatabase()
database.close()
const future = new DatabaseSync(path)
if (hasParameter) {
future.prepare(statement).run(new Date().toISOString())
} else {
future.exec(statement)
}
future.close()
const unsupported = new KnowledgeDatabase(path)
expect(() => unsupported.initialize()).toThrow(
'newer than supported version 11'
)
const inspection = new DatabaseSync(path)
expect(inspection.prepare('PRAGMA user_version').get()).toEqual({
user_version: hasParameter ? 11 : 12
})
expect(
inspection
.prepare('SELECT MAX(version) AS version FROM schema_migrations')
.get()
).toEqual({ version: hasParameter ? 12 : 11 })
inspection.close()
})
it('keeps graph generation off unless explicitly enabled', async () => {
const { database } = await createDatabase()
const defaultLibrary = database.createKnowledgeBase({
+36
View File
@@ -4426,6 +4426,31 @@ export class KnowledgeDatabase {
}
private migrate(database: DatabaseSync): void {
const migrationTable = database
.prepare(
`SELECT 1 AS found FROM sqlite_schema
WHERE type = 'table' AND name = 'schema_migrations'`
)
.get()
if (migrationTable) {
const versions = database
.prepare(
`SELECT
(SELECT COALESCE(MAX(version), 0) FROM schema_migrations)
AS migration_version,
user_version
FROM pragma_user_version`
)
.get()
if (
versions &&
asNumber(versions, 'migration_version') === DATABASE_VERSION &&
asNumber(versions, 'user_version') === DATABASE_VERSION
) {
return
}
}
database.exec('BEGIN IMMEDIATE')
try {
database.exec(`
@@ -4443,6 +4468,17 @@ export class KnowledgeDatabase {
`Knowledge database version ${currentVersion} is newer than supported version ${DATABASE_VERSION}`
)
}
const userVersionRow = database
.prepare('PRAGMA user_version')
.get()
const userVersion = userVersionRow
? asNumber(userVersionRow, 'user_version')
: 0
if (userVersion > DATABASE_VERSION) {
throw new Error(
`Knowledge database user version ${userVersion} is newer than supported version ${DATABASE_VERSION}`
)
}
if (currentVersion < 1) {
this.migrateToVersion1(database)
database
+114
View File
@@ -0,0 +1,114 @@
import { describe, expect, it, vi } from 'vitest'
import { runStartupPrerequisites } from './startup-prerequisites'
function deferred<T = void>(): {
promise: Promise<T>
resolve: (value: T) => void
reject: (reason: unknown) => void
} {
let resolve!: (value: T) => void
let reject!: (reason: unknown) => void
const promise = new Promise<T>((resolvePromise, rejectPromise) => {
resolve = resolvePromise
reject = rejectPromise
})
return { promise, resolve, reject }
}
describe('runStartupPrerequisites', () => {
it('starts independent work before synchronous initialization and waits for every branch', async () => {
const order: string[] = []
const deepSeekHome = deferred()
const knowledgeAndGateway = deferred()
const configuredRuntime = deferred<{ id: string }>()
const result = runStartupPrerequisites({
prepareDeepSeekHome: () => {
order.push('deepseek')
return deepSeekHome.promise
},
initializeKnowledgeAndGateway: () => {
order.push('knowledge')
return knowledgeAndGateway.promise
},
hydrateConfiguredRuntime: () => {
order.push('runtime')
return configuredRuntime.promise
},
initializeAssistant: () => {
order.push('assistant')
}
})
const completed = vi.fn()
void result.then(completed)
expect(order).toEqual([
'deepseek',
'knowledge',
'runtime',
'assistant'
])
configuredRuntime.resolve({ id: 'configured' })
knowledgeAndGateway.resolve()
await Promise.resolve()
expect(completed).not.toHaveBeenCalled()
deepSeekHome.resolve()
await expect(result).resolves.toEqual({ id: 'configured' })
expect(completed).toHaveBeenCalledOnce()
})
it('settles every started branch before propagating synchronous initialization failure', async () => {
const assistantError = new Error('assistant failed')
const deepSeekHome = deferred()
const knowledgeAndGateway = deferred()
const configuredRuntime = deferred<{ id: string }>()
const result = runStartupPrerequisites({
prepareDeepSeekHome: () => deepSeekHome.promise,
initializeKnowledgeAndGateway: () =>
knowledgeAndGateway.promise,
hydrateConfiguredRuntime: () => configuredRuntime.promise,
initializeAssistant: () => {
throw assistantError
}
})
const rejected = vi.fn()
void result.catch(rejected)
deepSeekHome.resolve()
knowledgeAndGateway.resolve()
await Promise.resolve()
expect(rejected).not.toHaveBeenCalled()
configuredRuntime.resolve({ id: 'unused' })
await expect(result).rejects.toBe(assistantError)
expect(rejected).toHaveBeenCalledOnce()
})
it('does not publish an async branch failure until the other branches settle', async () => {
const runtimeError = new Error('runtime failed')
const deepSeekHome = deferred()
const knowledgeAndGateway = deferred()
const result = runStartupPrerequisites({
prepareDeepSeekHome: () => deepSeekHome.promise,
initializeKnowledgeAndGateway: () =>
knowledgeAndGateway.promise,
hydrateConfiguredRuntime: () =>
Promise.reject(runtimeError),
initializeAssistant: () => undefined
})
const rejected = vi.fn()
void result.catch(rejected)
await Promise.resolve()
expect(rejected).not.toHaveBeenCalled()
deepSeekHome.resolve()
knowledgeAndGateway.resolve()
await expect(result).rejects.toBe(runtimeError)
expect(rejected).toHaveBeenCalledOnce()
})
})
+61
View File
@@ -0,0 +1,61 @@
export type StartupPrerequisiteDependencies<ConfiguredRuntime> = {
prepareDeepSeekHome: () => Promise<void>
initializeKnowledgeAndGateway: () => Promise<void>
hydrateConfiguredRuntime: () => Promise<ConfiguredRuntime>
initializeAssistant: () => void
}
function startObserved<T>(operation: () => Promise<T>): Promise<T> {
let started: Promise<T>
try {
started = Promise.resolve(operation())
} catch (error) {
started = Promise.reject(error)
}
void started.catch(() => undefined)
return started
}
export async function runStartupPrerequisites<ConfiguredRuntime>(
dependencies: StartupPrerequisiteDependencies<ConfiguredRuntime>
): Promise<ConfiguredRuntime> {
const deepSeekHomeReady = startObserved(
dependencies.prepareDeepSeekHome
)
const knowledgeAndGatewayReady = startObserved(
dependencies.initializeKnowledgeAndGateway
)
const configuredRuntimeReady = startObserved(
dependencies.hydrateConfiguredRuntime
)
let assistantInitializationFailed = false
let assistantInitializationError: unknown
try {
dependencies.initializeAssistant()
} catch (error) {
assistantInitializationFailed = true
assistantInitializationError = error
}
const [deepSeekHome, knowledgeAndGateway, configuredRuntime] =
await Promise.allSettled([
deepSeekHomeReady,
knowledgeAndGatewayReady,
configuredRuntimeReady
] as const)
if (assistantInitializationFailed) {
throw assistantInitializationError
}
if (deepSeekHome.status === 'rejected') {
throw deepSeekHome.reason
}
if (knowledgeAndGateway.status === 'rejected') {
throw knowledgeAndGateway.reason
}
if (configuredRuntime.status === 'rejected') {
throw configuredRuntime.reason
}
return configuredRuntime.value
}