InstructionMemoryMiddleware

org.llm4s.agent.harness.InstructionMemoryMiddleware
See theInstructionMemoryMiddleware companion object
@Experimental
final class InstructionMemoryMiddleware(val paths: Vector[VPath], val backend: FileBackend, val maxFileTokens: Int, val maxTotalTokens: Int, val maxCachedRuns: Int, val id: MiddlewareId) extends AgentMiddleware

Instruction memory for an agent (design ยง4.36): the AGENTS.md files at paths, read through backend in order - for example the user's, then the project's - and shown to the model as one cacheable prompt section, each file under a heading naming its path. A later file refines an earlier one.

  • When. The files are read on a run's first model call, from that step's snapshot, and kept for the run (a bounded cache, maxCachedRuns runs). A run recovered or resumed reads again: a state backend's files come back with the checkpoint, while a store's or a host's may have changed in between.
  • Editing. The agent edits a file with edit_file, over the same backend, when the backend accepts the write and the permission rules allow Write on its path; the change shows from the next run. Make a scope read-only with a deny rule, or by mounting it on a backend that refuses writes.
  • Bounds. Each file is read at most maxFileTokens estimated tokens, and the section - guide, headings and markers included - is at most maxTotalTokens. A file over either is shown cut and marked; the files after the section is full are left out. Each is named, by path, in a durable HarnessEvents.DocumentsReported.
  • Problems. A missing file is skipped, and so is one that is only whitespace (one cut at its limit is shown, cut). A file the backend refuses is skipped and reported. A backend error that is not a refusal fails the step, which recover runs again.

Instruction memory is a few whole files the agent always sees; semantic memory (llm4s-agent-memory) is facts recalled per query. The middleware writes nothing: its writes are the backend's keys, so a state backend's files are registered with the graph even with no file tool.

Attributes

Companion
object
Graph
Supertypes
class Object
trait Matchable
class Any

Members list

Value members

Concrete methods

def instructions(context: ModelContext): Result[Vector[Instructions]]

The files this run shows, read on its first call.

The files this run shows, read on its first call.

Attributes

override def promptSections(context: ModelContext): Result[Vector[PromptSection]]

Content for the system prompt of each model request: collected before every model step from the committed state, in stack order, and never stored. Each middleware bounds its own; the agent bounds them all together (maxPromptSectionTokens). Left fails the run.

Content for the system prompt of each model request: collected before every model step from the committed state, in stack order, and never stored. Each middleware bounds its own; the agent bounds them all together (maxPromptSectionTokens). Left fails the run.

Attributes

Definition Classes
override def writes: Set[StateKey[_, _]]

The state keys this middleware's hooks may write: an update from beforeAgent, wrapModelCall or afterAgent, or one wrapToolCall adds to a Success. A hook's write to any other key fails the run.

The state keys this middleware's hooks may write: an update from beforeAgent, wrapModelCall or afterAgent, or one wrapToolCall adds to a Success. A hook's write to any other key fails the run.

Attributes

Definition Classes

Inherited methods

def afterAgent(answer: String, context: ModelContext): Result[BoundaryResult]

Sees the run's final answer: returns it, possibly changed, with an update to this middleware's writes, or Left to block the run.

Sees the run's final answer: returns it, possibly changed, with an update to this middleware's writes, or Left to block the run.

Attributes

Inherited from:
AgentMiddleware
def beforeAgent(input: String, context: ModelContext): Result[BoundaryResult]

Sees the run's input before anything else runs: returns it, possibly changed, with an update to this middleware's writes that the turn's first model call sees, or Left to block the run.

Sees the run's input before anything else runs: returns it, possibly changed, with an update to this middleware's writes that the turn's first model call sees, or Left to block the run.

Attributes

Inherited from:
AgentMiddleware
def placement(other: AgentMiddleware): Option[Placement]

Where this middleware must run relative to other, when both are present; None, the default, when it does not matter. A requirement is checked, never arranged: MiddlewareStack.of - so AgentBuilder.build() - refuses a stack in which this middleware does not run outside other, and a Placement.OutsideAtBoundary is checked across an agent family too. Register the two in the right order, or name other in runsBefore. Name other by its type: ids are configurable.

Where this middleware must run relative to other, when both are present; None, the default, when it does not matter. A requirement is checked, never arranged: MiddlewareStack.of - so AgentBuilder.build() - refuses a stack in which this middleware does not run outside other, and a Placement.OutsideAtBoundary is checked across an agent family too. Register the two in the right order, or name other in runsBefore. Name other by its type: ids are configurable.

Attributes

Inherited from:
AgentMiddleware

Middleware this one must run inside of (be wrapped by); each must be registered in the same stack.

Middleware this one must run inside of (be wrapped by); each must be registered in the same stack.

Attributes

Inherited from:
AgentMiddleware

Middleware this one must run outside of (wrap); each must be registered in the same stack.

Middleware this one must run outside of (wrap); each must be registered in the same stack.

Attributes

Inherited from:
AgentMiddleware
def tools: Vector[AgentTool[_]]

Tools this middleware contributes; they join the loop's tool set and are validated like any other.

Tools this middleware contributes; they join the loop's tool set and are validated like any other.

Attributes

Inherited from:
AgentMiddleware

Wraps one model call. A wrapper may rewrite the request (inject a note, filter tools), call next more than once (retry, fallback), transform its response, add an update to its writes (ModelResponse.addUpdate), or return Left, which fails the run. Only an AgentMiddleware.Asking wrapper suspends, by asking its question. Every call next makes is counted in the thread's usage, whichever response the wrapper returns.

Wraps one model call. A wrapper may rewrite the request (inject a note, filter tools), call next more than once (retry, fallback), transform its response, add an update to its writes (ModelResponse.addUpdate), or return Left, which fails the run. Only an AgentMiddleware.Asking wrapper suspends, by asking its question. Every call next makes is counted in the thread's usage, whichever response the wrapper returns.

Filtering ModelRequest.tools shapes what the model is offered and is not a permission control: a tool the model calls anyway still runs through wrapToolCall, where denial belongs.

Attributes

Inherited from:
AgentMiddleware
def wrapToolCall(request: ToolCallRequest, context: ToolContext)(next: () => ToolOutcome): ToolOutcome

Wraps one tool call, after its arguments were validated. A wrapper denies with ToolOutcome.Error("Denied: ..."), asks for approval with NeedsApproval(reason) (unless context.approved), fails the run with Fatal, and short-circuits by not calling next. It may call next more than once (retry) and transform the outcome next returns.

Wraps one tool call, after its arguments were validated. A wrapper denies with ToolOutcome.Error("Denied: ..."), asks for approval with NeedsApproval(reason) (unless context.approved), fails the run with Fatal, and short-circuits by not calling next. It may call next more than once (retry) and transform the outcome next returns.

Attributes

Inherited from:
AgentMiddleware

Concrete fields

This middleware's identifier, unique in its stack; must match [a-zA-Z0-9_-]{1,64}.

This middleware's identifier, unique in its stack; must match [a-zA-Z0-9_-]{1,64}.

Attributes

val maxCachedRuns: Int
val maxFileTokens: Int
val maxTotalTokens: Int
val paths: Vector[VPath]