fix: stop subagent history from exhausting disk space
GoodBuddy Agents / Validate Agent source (push) Canceled after 0s
GoodBuddy Agents / Build darwin arm64 Agent (push) Canceled after 0s
GoodBuddy Agents / Build linux arm64 Agent (push) Canceled after 0s
GoodBuddy Agents / Build linux x64 Agent (push) Canceled after 0s
Cross-platform packages / Validate source (push) Canceled after 0s
Cross-platform packages / Authorize desktop packaging (push) Canceled after 0s
Cross-platform packages / linux arm64 (push) Canceled after 0s
Cross-platform packages / macos arm64 (push) Canceled after 0s
Cross-platform packages / windows arm64 (push) Canceled after 0s
Cross-platform packages / linux x64 (push) Canceled after 0s
Cross-platform packages / macos x64 (push) Canceled after 0s
Cross-platform packages / windows x64 (push) Canceled after 0s
Cross-platform packages / Publish GitHub and OSS release (push) Canceled after 0s

Repeated full subagent progress snapshots could grow the desktop database to
many gigabytes during ordinary long-running tasks. Local and managed SSH
writes now retain lossless progress changes while preserving conversation
snapshots, event identities, remote replay deduplication and transaction rollback.

Upgrade existing history in bounded worker-thread batches, show progress and
retry controls, and reclaim freed disk space after conversion. Schema 34 cannot
be opened by older clients; a pre-upgrade backup is required for client rollback.
Document reusable database migration guidance and the verified large-database,
portable, local Runtime and Linux Host evidence.

Prepare Desktop 0.13.1 with the approved bilingual notes and aligned feature
lists. Agent remains 0.11.24. Final candidate validation and production builds
will run on main CI, as requested, without additional local release testing.

Release note: 修复长任务和子任务造成的数据库异常膨胀;升级时自动整理旧记录并回收空间,保留聊天、执行详情和结果,并支持退出后继续处理。
This commit is contained in:
mesalogo
2026-09-13 20:50:33 +08:00
parent 1c22e1a06d
commit 49377206cc
32 changed files with 1207 additions and 27 deletions
+34 -6
View File
@@ -95,8 +95,9 @@ import {
setMagicNoteChecklistCompletion
} from '../magic-notes/rich-content'
import { computeNextHeartbeatRun } from './heartbeat-recurrence'
import { SubagentProgressStorage } from './subagent-progress-storage'
export const ASSISTANT_DATABASE_SCHEMA_VERSION = 33
export const ASSISTANT_DATABASE_SCHEMA_VERSION = 34
export type RemoteTaskEventInput = {
taskId: string
@@ -1750,6 +1751,7 @@ function deleteProjectRecords(
export class AssistantDatabase {
private database?: DatabaseSync
private subagentProgress?: SubagentProgressStorage
private channelEventWrites = 0
private channelOutboxWrites = 0
@@ -1780,6 +1782,7 @@ export class AssistantDatabase {
`)
this.migrate(database)
this.database = database
this.subagentProgress = new SubagentProgressStorage(database)
this.channelEventWrites = (
database
.prepare('SELECT COUNT(*) AS count FROM channel_events')
@@ -2015,6 +2018,7 @@ export class AssistantDatabase {
close(): void {
this.database?.close()
this.database = undefined
this.subagentProgress = undefined
}
clearAssistantData(): void {
@@ -4931,7 +4935,9 @@ export class AssistantDatabase {
kind: string,
payload: unknown
): void {
this.requireDatabase()
const database = this.requireDatabase()
const payloadJson = this.subagentProgress!.serialize(taskId, kind, payload)
const result = database
.prepare(
`INSERT INTO task_events
(task_id, run_id, kind, payload_json, created_at)
@@ -4940,9 +4946,12 @@ export class AssistantDatabase {
.run(
taskId,
kind.slice(0, 64),
JSON.stringify(payload),
payloadJson,
new Date().toISOString()
)
this.subagentProgress!.inserted(
taskId, kind, Number(result.lastInsertRowid), payloadJson
)
}
appendRemoteTaskEventOnce(input: RemoteTaskEventInput): boolean {
@@ -5335,6 +5344,9 @@ export class AssistantDatabase {
database: DatabaseSync,
event: ValidatedRemoteTaskEvent
): boolean {
const payloadJson = this.subagentProgress!.serialize(
event.taskId, event.kind, JSON.parse(event.payloadJson)
)
const result = database
.prepare(
`INSERT OR IGNORE INTO task_events
@@ -5346,7 +5358,7 @@ export class AssistantDatabase {
.run(
event.taskId,
event.kind,
event.payloadJson,
payloadJson,
new Date().toISOString(),
event.bindingId,
event.operationId,
@@ -5354,11 +5366,14 @@ export class AssistantDatabase {
event.eventIndex
)
if (result.changes === 1) {
this.subagentProgress!.inserted(
event.taskId, event.kind, Number(result.lastInsertRowid), payloadJson
)
return true
}
const existing = database
.prepare(
`SELECT task_id, kind, payload_json
`SELECT id, task_id, kind, payload_json
FROM task_events
WHERE remote_binding_id = ?
AND remote_operation_id = ?
@@ -5372,6 +5387,7 @@ export class AssistantDatabase {
event.eventIndex
) as
| {
id: number
task_id: string
kind: string
payload_json: string
@@ -5380,7 +5396,10 @@ export class AssistantDatabase {
if (
existing?.task_id === event.taskId &&
existing.kind === event.kind &&
existing.payload_json === event.payloadJson
(existing.payload_json === event.payloadJson ||
(event.kind === 'subagent' && this.subagentProgress!.matches(
event.taskId, existing.id, JSON.parse(event.payloadJson)
)))
) {
return false
}
@@ -9653,6 +9672,15 @@ export class AssistantDatabase {
COMMIT;
`)
}
if (version.user_version < 34) {
database.exec(`
BEGIN IMMEDIATE;
CREATE INDEX IF NOT EXISTS task_events_subagent_idx
ON task_events(task_id, id) WHERE kind = 'subagent';
PRAGMA user_version = 34;
COMMIT;
`)
}
}
private requireDatabase(): DatabaseSync {