InMemoryCheckpointer

org.llm4s.agent.graph.InMemoryCheckpointer
final class InMemoryCheckpointer(clock: Clock) extends Checkpointer

A Checkpointer in memory. Checkpoints and pending writes are stored as JSON and decoded on read, exactly as a database-backed store would, so nothing executable survives a round trip. Claims expire, and prune judges age, by clock. Fencing tokens come from one counter for the whole store, so they never repeat for a thread, even after it is deleted. awaitEventsAfter wakes on the store's own commits, so every runtime sharing the instance sees a commit as soon as it lands, without polling.

Attributes

Graph
Supertypes
trait Checkpointer
class Object
trait Matchable
class Any

Members list

Value members

Constructors

def this()

For callers that cannot use default arguments (Java, Kotlin): claims expire by the system clock.

For callers that cannot use default arguments (Java, Kotlin): claims expire by the system clock.

Attributes

Concrete methods

override def awaitEventsAfter(threadId: ThreadId, afterSeq: Long, limit: Int, timeout: FiniteDuration): Result[Vector[EventRecord]]

Waits on the store's own commits rather than polling; see Checkpointer.awaitEventsAfter.

Waits on the store's own commits rather than polling; see Checkpointer.awaitEventsAfter.

Attributes

Definition Classes
def checkpoint(threadId: ThreadId, checkpointId: String): Result[Option[Checkpoint]]

Checkpoint checkpointId of the thread's history, latest included; None if it is not there.

Checkpoint checkpointId of the thread's history, latest included; None if it is not there.

Attributes

def claim(threadId: ThreadId, request: ClaimRequest): Result[RunClaim]

Claims threadId for request.holder until request.ttl from now, by the store's clock, if no other claim on it is live, and returns the claim with a new FencingToken. A live claim - whoever holds it, the same holder included - is Left(GraphError.ThreadBusy) naming its holder, with nothing changed. A thread need not have a checkpoint to be claimed.

Claims threadId for request.holder until request.ttl from now, by the store's clock, if no other claim on it is live, and returns the claim with a new FencingToken. A live claim - whoever holds it, the same holder included - is Left(GraphError.ThreadBusy) naming its holder, with nothing changed. A thread need not have a checkpoint to be claimed.

Attributes

def commit(threadId: ThreadId, commit: Commit): Result[Vector[EventRecord]]

Applies commit atomically, fenced by its token, and returns its events with their sequence numbers.

Applies commit atomically, fenced by its token, and returns its events with their sequence numbers.

Attributes

def compactEvents(threadId: ThreadId, beforeSeq: Long): Result[Unit]

Drops events with seq < beforeSeq; replay can then start no earlier than beforeSeq.

Drops events with seq < beforeSeq; replay can then start no earlier than beforeSeq.

Attributes

def deleteThread(threadId: ThreadId): Result[Unit]

Removes everything stored for the thread - its checkpoint history, its pending writes, its event log and its claim - so that its id names a new thread again, whose events are numbered from 1; tokens issued after it are still greater than every token issued before. An unknown thread is Right(()). Use GraphRuntime.deleteThread, which claims the thread first, so it refuses a thread with a live run in any runtime, and checks the tenant; the store itself checks neither.

Removes everything stored for the thread - its checkpoint history, its pending writes, its event log and its claim - so that its id names a new thread again, whose events are numbered from 1; tokens issued after it are still greater than every token issued before. An unknown thread is Right(()). Use GraphRuntime.deleteThread, which claims the thread first, so it refuses a thread with a live run in any runtime, and checks the tenant; the store itself checks neither.

Attributes

def eventsAfter(threadId: ThreadId, afterSeq: Long, limit: Int): Result[Vector[EventRecord]]

Up to limit events with seq > afterSeq, ascending.

Up to limit events with seq > afterSeq, ascending.

Attributes

def history(threadId: ThreadId, before: Option[String], limit: Int): Result[Vector[Checkpoint]]

Up to limit of the thread's checkpoints, newest first - the latest is the first of the first page - starting after checkpoint before when it is given, so a caller pages through the history by passing the last id of each page. A before that is not in the history is Left(GraphError.CheckpointNotFound); a thread with no checkpoint has an empty history.

Up to limit of the thread's checkpoints, newest first - the latest is the first of the first page - starting after checkpoint before when it is given, so a caller pages through the history by passing the last id of each page. A before that is not in the history is Left(GraphError.CheckpointNotFound); a thread with no checkpoint has an empty history.

Attributes

def latest(threadId: ThreadId): Result[Option[StoredCheckpoint]]

The thread's latest checkpoint and its pending writes; None for a new thread.

The thread's latest checkpoint and its pending writes; None for a new thread.

Attributes

def prune(threadId: ThreadId, policy: RetentionPolicy): Result[Unit]

Removes the checkpoints and events of the thread that policy does not keep (see RetentionPolicy), by the store's clock. The latest checkpoint and its pending writes are always kept. Pruning a checkpoint also removes the events before the oldest checkpoint kept; maxAge and maxEvents may remove more, including the latest checkpoint's. Removing events raises the replay floor as compactEvents does. Needs no claim: it touches nothing a run reads or writes. An unknown thread is Right(()).

Removes the checkpoints and events of the thread that policy does not keep (see RetentionPolicy), by the store's clock. The latest checkpoint and its pending writes are always kept. Pruning a checkpoint also removes the events before the oldest checkpoint kept; maxAge and maxEvents may remove more, including the latest checkpoint's. Removing events raises the replay floor as compactEvents does. Needs no claim: it touches nothing a run reads or writes. An unknown thread is Right(()).

Attributes

def release(threadId: ThreadId, token: FencingToken): Result[Unit]

Ends the claim whose token is token, so the thread can be claimed again at once. A token that is not the thread's current claim changes nothing and is Right(()): a run that lost its claim must never release its successor's.

Ends the claim whose token is token, so the thread can be claimed again at once. A token that is not the thread's current claim changes nothing and is Right(()): a run that lost its claim must never release its successor's.

Attributes

def renew(threadId: ThreadId, token: FencingToken, ttl: FiniteDuration): Result[RunClaim]

Extends the claim whose token is token to ttl from now, by the store's clock, and returns it. Left(GraphError.StaleClaim) if token is not the thread's current claim (another run took it over, it was released, or the thread was deleted). An expired claim nobody replaced is renewed.

Extends the claim whose token is token to ttl from now, by the store's clock, and returns it. Left(GraphError.StaleClaim) if token is not the thread's current claim (another run took it over, it was released, or the thread was deleted). An expired claim nobody replaced is renewed.

Attributes