feat(durable): group commit and batch Storage.commit

A Session no longer holds its line while a commit is stored. Commits that
arrive while one storage call is in flight go out together in the next call,
each with its own seq and outcome; a job runs until it touches a key an
unpublished commit wrote, then waits for that commit's publication. Outcomes
are delivered in line order; publication is in line order, one commit per
macrotask. The scheduler's decisions run as regions that record the keys they
read and rerun after a wait, with side effects only after a clean check.

Storage.commit(batches, receive, context) replaces commit(writes, adopt,
context): prefix semantics (Durable's own checks refuse a batch and keep the
ones before it; any other failure rejects the call), receipts per stored
batch, optional publishing() scope. Memory, SQLite, JSONL, IndexedDB and
StoreStorage implement it natively; StoreStorage through the new
ChordStore.commitSeries (one store transaction per call), replacing
commitInBatch.

A normal run makes no storage reads: bounded record cache, conversation
tails, task-document index, kept context ranges. A tool slot's running status
and a generation's attempt are stored with the next commit (12 instead of 14
commits per run).

One Harness with 128 conversations over storage with a 4 ms round trip: about
5 -> 440 agent runs per second. Design: packages/durable/docs/group-commit.md.
This commit is contained in:
Mario Zechner 2026-10-30 10:40:53 +00:00
parent 908aa7b74b
commit e5c6182bab
81 changed files with 8626 additions and 1475 deletions

View file

@ -68,8 +68,11 @@ const BUDGETS = {
// parse streamed tool-call arguments with pi-ai's utils/streaming-json.ts (and its json-parse.ts) to append what
// argument strings grew by (harness/partial-changes.ts). Chord's watches fold pending ops with Delta's
// pending queue (delta/pending.ts). `registryReader` (harness/registry-reader.ts) reads a Chord v2 registry
// value through type-only imports.
maxFiles: 78,
// value through type-only imports. The Session caches hot Storage reads (session/cached-storage.ts) and keeps
// each conversation's newest entry and head marker (session/conversation-tails.ts). Group commit sends batches
// through `commit()`, or one `commit()` each (storage/commit-batch.ts), from a writer off the Session line
// (session/writer.ts) that gates reads by the keys of unpublished writes (session/keys.ts).
maxFiles: 83,
forbid: [
"packages/ai/src/index.ts",
"packages/ai/src/utils/typebox-helpers.ts",