org.llm4s.agent.harness.memory

Members list

Type members

Classlikes

@Experimental
final case class MemoryConsolidated(groups: Int, removed: Int, evicted: Int)

groups groups were consolidated: removed memories replaced by one summary each, evicted evicted.

groups groups were consolidated: removed memories replaced by one summary each, evicted evicted.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
@Experimental
final case class MemoryConsolidation

When SemanticMemoryMiddleware consolidates: after each turn, the manager's consolidateMemories over memories older than olderThan, in groups of at least minCount.

When SemanticMemoryMiddleware consolidates: after each turn, the manager's consolidateMemories over memories older than olderThan, in groups of at least minCount.

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
@Experimental

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
@Experimental
object MemoryEvents

The durable events of SemanticMemoryMiddleware, each an org.llm4s.agent.graph.EventType to match a StreamEvent with. They carry counts and names only, never memory content or an error message (rule 9).

The durable events of SemanticMemoryMiddleware, each an org.llm4s.agent.graph.EventType to match a StreamEvent with. They carry counts and names only, never memory content or an error message (rule 9).

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
@Experimental
final case class MemoryRecall

What SemanticMemoryMiddleware recalls before a turn: at most maxRecallTokens (estimated at four characters a token, as the agent's prompt-section budget is), of the memories filter accepts.

What SemanticMemoryMiddleware recalls before a turn: at most maxRecallTokens (estimated at four characters a token, as the agent's prompt-section budget is), of the memories filter accepts.

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
@Experimental
object MemoryRecall

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
@Experimental
final case class MemoryRecorded(added: Int, evicted: Int)

The turn's recording stored added memories, and evicted evicted to keep the store within its bounds.

The turn's recording stored added memories, and evicted evicted to keep the store within its bounds.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
@Experimental
final case class MemoryRecording

How SemanticMemoryMiddleware records a turn: each memory's content cut to maxRecordChars code points.

How SemanticMemoryMiddleware records a turn: each memory's content cut to maxRecordChars code points.

Attributes

Companion
object
Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
@Experimental

Attributes

Companion
class
Supertypes
trait Product
trait Mirror
class Object
trait Matchable
class Any
Self type
@Experimental
final case class MemorySkipped(operation: String, error: String)

operation (memory.recall, memory.record, memory.consolidate or memory.resolve) failed with an error of type error (its class's simple name), and was skipped.

operation (memory.recall, memory.record, memory.consolidate or memory.resolve) failed with an error of type error (its class's simple name), and was skipped.

Attributes

Supertypes
trait Serializable
trait Product
trait Equals
class Object
trait Matchable
class Any
Show all
@Experimental
final class SemanticMemoryMiddleware(stores: Option[TenantId] => Result[MemoryStore], manager: (MemoryStore, LLMClient) => MemoryManager, client: LLMClient, val recall: Option[MemoryRecall], val record: Option[MemoryRecording], val consolidate: Option[MemoryConsolidation], val bounds: MemoryBounds, clock: Clock, val runsBefore: Set[MiddlewareId], val id: MiddlewareId) extends AgentMiddleware

Long-term semantic memory for an agent (design §4.31): before each turn it recalls what earlier threads of the same tenant recorded and shows it to the model; after the turn it records the exchange, and, when consolidate is set, replaces groups of old memories with a summary.

Long-term semantic memory for an agent (design §4.31): before each turn it recalls what earlier threads of the same tenant recorded and shows it to the model; after the turn it records the exchange, and, when consolidate is set, replaces groups of old memories with a summary.

  • Tenant scope. stores is asked once per tenant (RunContext.config.tenantId) for that tenant's store; the store is held in one cell per tenant, whose writes are serialised. Every thread of a tenant shares it; no two tenants may share a store instance (refused). A failed resolution is asked again on the next turn.
  • The manager is built for each hook call by manager(view, context.accounted(client)), over a view of the tenant's store whose writes are the middleware's effects, so every model call it makes is counted in the thread's usage.
  • Recall (beforeAgent) runs getRelevantContext on the turn's input, cuts it to maxRecallTokens * 4 characters and stores it in SemanticMemoryMiddleware.RecalledKey; every model step of the turn shows it as the prompt section semantic-memory. A resolution or configuration failure refuses the input before any model call; a failed search is skipped, announced by MemoryEvents.Skipped.
  • Recording (afterAgent) records the turn's query and answer through the manager as one replayable effect (memory.record, C4): on a org.llm4s.agent.memory.TransactionalMemoryStore a replay after a crash returns the recorded outcome and never writes twice; on any other store a replay of a write that may have run is refused. Each memory is cut to maxRecordChars.
  • Consolidation (afterAgent, after recording) runs the manager's consolidateMemories on memories older than olderThan; each group it replaces is one effect (memory.consolidate, keyed by the group's ids). It needs a transactional store: on any other, the input is refused.
  • Bounds. Every write evicts, in its own transaction, the memories of lowest importance, oldest first, beyond bounds, so a tenant's store stays bounded whether or not consolidation is on.
  • Failures after the answer are skipped and announced by MemoryEvents.Skipped: the answer is never retracted because memory could not be written. A crash is replayed by recover from C4's records.

Register it outside guardrail middleware - before it, or with runsBefore naming it - so that a blocked answer is never recorded: afterAgent runs in reverse stack order, and a guardrail's block stops the others. An effect that applied stays applied: a Block restores thread state, not the store.

The key is registered only by an agent family with a SemanticMemoryMiddleware: adding one to an existing agent changes its graph's structure.

Value parameters

bounds

the most each tenant's store keeps

client

the client the manager calls a model with; every call is accounted to the run

clock

where consolidation reads "now" from

consolidate

when to consolidate old memories after a turn; None never

id

this middleware's id

manager

builds the manager over a store and a client, e.g. LLMMemoryManager(config, _, _)

recall

what to recall before a turn; None recalls nothing

record

how to record a turn; None records nothing

runsBefore

middleware this one must run outside of, such as MiddlewareId("guardrails")

stores

the store of each tenant (None for runs without one): a store scoped to that tenant

Attributes

Companion
object
Supertypes
class Object
trait Matchable
class Any
@Experimental

Attributes

Companion
class
Supertypes
class Object
trait Matchable
class Any
Self type