Motivation
The only bundled HistoryProvider is InMemoryHistoryProvider, so a session does not survive a
process restart without a custom implementation. Of the reference implementations only Python
ships a file-backed one (FileHistoryProvider, JSON Lines); .NET has in-memory, Cosmos DB and
Valkey providers, and Go has in-memory only. Adopting Python's on-disk format means an external
provider (blob storage, a database) can be written against a format this framework also reads.
Proposed API
Node's fs is required, so this lands on a Node-only subpath rather than the runtime-agnostic
root entry, which has to keep working on Deno, Bun, edge runtimes and in browsers:
import { FileHistoryProvider } from '@polymind-inc/agent-framework/node';
const provider = new FileHistoryProvider({ storagePath: '/var/lib/sessions' });
Behaviour
- One append-only file per session:
{storagePath}/{sessionId}.jsonl. The directory is created
when missing. The default sourceId is file_history, matching Python.
- One message per line:
JSON.stringify(serializeMessage(msg)) followed by \n, appended, UTF-8.
getMessages returns [] when the file does not exist. Blank lines are skipped rather than
rejected; a line that fails to parse raises an error naming the line number.
- A session id that is not safe as a filename is encoded rather than rejected (Python uses a
~session- prefix plus an encoded form), and the resolved path is verified to stay inside
storagePath.
- Appends to one file are serialized through a per-path async lock, so concurrent runs on the same
session cannot interleave partial lines.
Acceptance criteria
- Round trip: save through one instance, read the transcript back through another.
- Order is preserved across several turns of appending.
- A session id containing
../, an absolute path or a path separator cannot write outside
storagePath.
- The JSONL layout is pinned by a test — external providers implement against it.
Motivation
The only bundled
HistoryProviderisInMemoryHistoryProvider, so a session does not survive aprocess restart without a custom implementation. Of the reference implementations only Python
ships a file-backed one (
FileHistoryProvider, JSON Lines); .NET has in-memory, Cosmos DB andValkey providers, and Go has in-memory only. Adopting Python's on-disk format means an external
provider (blob storage, a database) can be written against a format this framework also reads.
Proposed API
Node's
fsis required, so this lands on a Node-only subpath rather than the runtime-agnosticroot entry, which has to keep working on Deno, Bun, edge runtimes and in browsers:
Behaviour
{storagePath}/{sessionId}.jsonl. The directory is createdwhen missing. The default
sourceIdisfile_history, matching Python.JSON.stringify(serializeMessage(msg))followed by\n, appended, UTF-8.getMessagesreturns[]when the file does not exist. Blank lines are skipped rather thanrejected; a line that fails to parse raises an error naming the line number.
~session-prefix plus an encoded form), and the resolved path is verified to stay insidestoragePath.session cannot interleave partial lines.
Acceptance criteria
../, an absolute path or a path separator cannot write outsidestoragePath.