feat(coding-agent): ingest external entries in in-memory sessions (#8980)

* feat(coding-agent): ingest external entries in in-memory sessions

SessionManager.inMemory() takes the entries to start from, so a session
held outside the filesystem can be resumed as it was stored.

Replaying through appendMessage/appendCompaction cannot do this: ids are
minted fresh, so every stored firstKeptEntryId, targetId and fromId has to
be remapped, timestamps are rewritten, and parentId always comes from the
current leaf, so a branched tree needs the original branch() choreography
reproduced call by call.

The entry-adoption half of _setSessionFile becomes _loadEntries, which the
constructor also uses when there are entries but no file. Entries carrying
a session header keep it; without one, the header comes from the options
and the entries become its body.

* fix(coding-agent): carry the stored version through restored entries

inMemory() took SessionEntry[], which excludes SessionHeader, so an
external store could not pass the header it saved and the header branch of
_loadEntries was unreachable through the public API. A restore therefore
always synthesised a current-version header, and the migration that ran
next read that header and skipped: a v2 session kept its hookMessage roles
forever.

Widening to FileEntry[] lets the stored header through, version included.
Migration moves inside the header branch, where a version exists to compare
against; without a header the entries are adopted as current-version, which
is the only thing they can mean.
This commit is contained in:
Julien Barbay 2026-09-03 10:49:41 +02:00 • committed by GitHub
parent 1a773c8e7a
commit 2b768ba42c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 213 additions and 13 deletions

View file

@ -788,6 +788,11 @@ const { session: opened } = await createAgentSession({
sessionManager: SessionManager.open("/path/to/session.jsonl"),
});
// Resume a session kept outside the filesystem, e.g. in a database
const { session: restored } = await createAgentSession({
sessionManager: SessionManager.inMemory(process.cwd(), { id: sessionId }, entries),
});
// List sessions
const currentProjectSessions = await SessionManager.list(process.cwd());
const allSessions = await SessionManager.listAll(process.cwd());