How it works
AgentRuntimeInterface is the public surface: run() executes synchronously, enqueue() persists a QUEUED row with the serialised request and dispatches an AgentRunQueuedMessage, and approve(), submitInput() and cancel() act on a run by uuid. Neither run() nor approve() throws for a run outcome; the AgentRunResult is already settled and says COMPLETED, AWAITING_APPROVAL, AWAITING_INPUT, FAILED and so on. AgentRunQueuedHandler calls runQueued(), which claims the row atomically, so exactly one worker wins. The run executes under the identity of the person who started it, also on a worker.
A worker holds a lease of AgentRuntime::LEASE_SECONDS (900) and renews it at every step boundary. Before a writing tool executes, the executor stamps the tool's effect on the run row. A run found mid NON_IDEMPOTENT_WRITE is dead-lettered, never retried. Other retryable failures are requeued with exponential backoff, up to AgentRuntime::MAX_REQUEUES. Cancellation is cooperative: the executor reads the row at each step boundary and stops when it is CANCELLED. An MCP call over HTTP can also be aborted mid-transfer through AgentRunCancellationSignal when the nr-vault client supports it.
ToolApprovalRule decides whether a call needs a human: the RequiresApprovalInterface marker, or a declared write effect from ToolEffectInterface. MCP tools are judged on the operator's declaration on the server row instead. At suspension the loop stores each pending call's ToolPreviewInterface lines with the state. ResumeCoordinator::approve() then claims the run and checks three gates before anything executes: the decision's turn digest must match the pending calls, the approver must be permitted to run every pending write, and for a turn that declares a write, the APPROVAL event must be stored. A refused gate puts the run back into WAITING_FOR_APPROVAL.
Before an approved call runs, ApprovalPreviewComparator re-runs its preview. If the lines differ from what the approver saw, nothing is written and the run suspends again with the current preview. A writing tool returns ToolResult::withWriteTarget(), which names the record, the WriteKind (CREATED, UPDATED, DELETED) and whether the write was complete. The executor records that as a tool_write step, and a write whose audit step cannot be stored fails the run. Writers run through ToolDataHandler, so a hook that throws after all records are written does not turn a finished write into a failure.
Netresearch\NrLlm\Service\Agent\AgentRuntimeInterface
Public run lifecycle: run(), enqueue(), runQueued(), approve(), submitInput(), cancel(), status() and events(). Returns settled AgentRunResult values instead of throwing for outcomes.
Netresearch\NrLlm\Service\Agent\Queue\AgentRunQueuedHandler
#[AsMessageHandler] for AgentRunQueuedMessage. Calls runQueued(), which claims the QUEUED row atomically and rehydrates the stored request.
Netresearch\NrLlm\Command\ReapStaleAgentRunsCommand
nrllm:agent:reap. Finds RUNNING runs with an expired lease, requeues those with a stored request and budget left, and dead-letters the rest.
Netresearch\NrLlm\Service\Agent\ResumeCoordinator
Decides a waiting run: access and four-eyes checks before the claim, then turn digest, approver permission and audit gates before execution under the owner's identity.
Netresearch\NrLlm\Service\Tool\ToolApprovalRule
The single rule for when a call needs approval: the RequiresApprovalInterface marker or a declared write effect; remote tools by their server-row declaration.
Netresearch\NrLlm\Service\Tool\ToolPreviewInterface
Opt-in for tools: previewCall() describes what a call would do, mayViewerReadPreview() decides whether the person looking at the card may see it. Previews must be deterministic.
Netresearch\NrLlm\Service\Tool\ApprovalPreviewComparator
Re-runs the previews of an approved turn at resume. A changed preview returns a re-suspended state with the current lines instead of executing.
Netresearch\NrLlm\Domain\ValueObject\ToolResult
A tool's answer. withWriteTarget() names the written record (RecordReference), its WriteKind and its WriteCompleteness for the run's audit stream.