feat(storage): move desktop SQLite ownership into a storage utility process

Main no longer opens desktop business SQLite. A single utility-process
storage owner holds the Assistant, Knowledge, attachment, document-result,
remote-binding and native model-ledger databases and runs whole domain
transactions; Main and Runtime callers use explicit async domain operations.

- Remove the Main readWithFallback path and the supervision worker's
  separate business write connection; manifests are scanned read-only and
  committed by the sole writer.
- Remote events are ACKed only after commit; process loss reports
  unconfirmed writes instead of replaying them.
- Use native utilityProcess messaging with one in-flight bound (32) and
  ordered waiting instead of capacity rejection and retries.
- Start the storage process before the window so startup overlaps.
- Keep short tool output in memory and store full output once in owned
  storage; paging, branching, restart and deletion reuse that copy.
- Put required runtime launch files under goodbuddy-prefixed owned temp
  directories and reclaim confirmed stale ones; stop writing duplicate
  parsed.md.
- Add lint guards for SQLite ownership and architecture, concurrency
  acceptance fixtures, and maintenance/architecture documentation.

Validation: typecheck and lint pass. Alternating baseline (edf019aa) vs
candidate runs show no regression on single-session, C01, C02, C04 and a
5-minute C06; Main p99 drops from ~21 ms to ~16.7 ms under concurrency.
Fresh portable copy (1.75M events) upgrade content unchanged; real-model
output paging passes with 4 external requests. Full npm test runs had
1-9 different timing-sensitive failures per run that pass when rerun.
Not covered: C03 review publication, C07 source body, app-level C05.
This commit is contained in:
mesalogo
2026-10-06 15:40:18 +08:00
parent bc677a3718
commit d80d42b032
229 changed files with 13632 additions and 3800 deletions
+18 -8
View File
@@ -309,6 +309,15 @@ export class AgentModelCallLedger {
}
}
/** Remote Agent uses the concrete ledger; desktop awaits its storage host. */
export type ModelCallLedger = {
[K in keyof AgentModelCallLedger]: (
...args: Parameters<AgentModelCallLedger[K]>
) => ReturnType<AgentModelCallLedger[K]> | Promise<ReturnType<AgentModelCallLedger[K]>>
}
export type ModelCallLedgerFactory = (path: string) => Promise<ModelCallLedger>
export type AgentModelGatewayContext = {
bindingId: string
operationId: string
@@ -319,11 +328,11 @@ export type AgentModelGatewayContext = {
}
export class AgentModelGateway {
readonly #ledger: AgentModelCallLedger
readonly #ledger: ModelCallLedger
readonly #fetch: typeof fetch
constructor(options: {
ledger: AgentModelCallLedger
ledger: ModelCallLedger
fetcher?: typeof fetch
}) {
this.#ledger = options.ledger
@@ -348,7 +357,7 @@ export class AgentModelGateway {
)
const requestDigest = sha256(prepared.canonicalRequest)
const callId = createAgentModelCallId(context)
this.#ledger.claim({
await this.#ledger.claim({
callId,
bindingId: context.bindingId,
operationId: context.operationId,
@@ -366,6 +375,7 @@ export class AgentModelGateway {
timer?.unref?.()
let response: Response
try {
signal.throwIfAborted()
response = await this.#fetch(prepared.url, {
method: 'POST',
redirect: 'error',
@@ -380,7 +390,7 @@ export class AgentModelGateway {
: signal.aborted
? 'cancelled'
: 'outcome-unknown'
this.#ledger.outcomeUnknown(callId, code)
await this.#ledger.outcomeUnknown(callId, code)
throw new AgentModelGatewayError(
code,
'Provider dispatch outcome is unknown'
@@ -403,7 +413,7 @@ export class AgentModelGateway {
: error instanceof BoundedResponseTooLargeError
? 'response-too-large'
: 'outcome-unknown'
this.#ledger.outcomeUnknown(callId, code)
await this.#ledger.outcomeUnknown(callId, code)
throw error instanceof AgentModelGatewayError
? error
: new AgentModelGatewayError(
@@ -418,7 +428,7 @@ export class AgentModelGateway {
clearTimeout(timer)
if (signal.aborted || timeout.signal.aborted) {
const code = timeout.signal.aborted ? 'timeout' : 'cancelled'
this.#ledger.outcomeUnknown(callId, code)
await this.#ledger.outcomeUnknown(callId, code)
throw new AgentModelGatewayError(
code,
'Provider response arrived after cancellation'
@@ -441,7 +451,7 @@ export class AgentModelGateway {
headers,
bodyBase64: Buffer.from(bytes).toString('base64')
})
this.#ledger.complete(callId)
await this.#ledger.complete(callId)
let finalized = false
return {
response: bridgeResponse,
@@ -453,7 +463,7 @@ export class AgentModelGateway {
)
}
finalized = true
this.#ledger.delivered(callId)
await this.#ledger.delivered(callId)
},
failDelivery: () => {
finalized = true