v0.24.0
nr_llm 0.24.0 — Agent Runtime hardening
A focused hardening release for the Agent Runtime: identity and authorization, queue delivery idempotency, fail-closed tool enforcement, and encryption of queued/suspended state at rest — the invariants a consumer extension needs before running agents asynchronously in production.
⚠️ Breaking release. Several public interfaces changed signature. Out-of-tree consumers of the agent runtime, tools, guardrails, the conversation service or the specialized services must adapt — see Breaking changes below and the linked ADRs.
Security hardening
- Agent-run identity & authorization (ADR-083 / 091 / 110) — every stateful agent entry point now carries an explicit
AiActorContextinstead of reading the ambient$GLOBALS['BE_USER'], and authorizes it fail-closed; a run/session UUID alone never suffices. Tools authorize against an explicitToolExecutionContextresolved to the acting backend user, so a run authorizes identically synchronously and in a queue worker. Service accounts are limited to declared scopes and fail closed with none. - Queue delivery idempotency (ADR-111 / 112) — tools declare a
ToolEffect(read-only / idempotent-write / non-idempotent-write). A writing tool's audit step is fail-closed, and a run reaped or failed mid non-idempotent-write is dead-lettered rather than retried — so an at-least-once retry never repeats a write that already ran. - Tool data-class enforcement, fail-closed & on by default (ADR-113 / 115) — the trust-zone tool gate observes only on an explicit
observe; a missing, malformed or unreadable setting now enforces. New installs enforce by default; existing installs are pinned toobserveby an upgrade wizard so the change does not silently strip tools from a working setup. - Agent run state encrypted at rest (ADR-114) — the queued request and suspended transcript in
tx_nrllm_agentrunare encrypted via nr-vault's managed-key envelope encryption (rotatable master key, per-column AAD). Rows written before this landed still rehydrate (no data migration).
Breaking changes
- Actor-context runtime surface (ADR-083) —
AgentRuntimeInterface::approve(),submitInput(),cancel(),status(),events()take a requiredAiActorContextfirst parameter;ToolInterface::execute()takes a requiredToolExecutionContext;AgentRunPersister::recordStep()now returnsbool. - Conversation service (ADR-091) —
ConversationServiceInterface::startSession()andsend()take a leadingAiActorContext; a session UUID alone no longer continues another user's conversation. - Per-configuration guardrail policies (ADR-106) —
GuardrailInterface/InputGuardrailInterfacegainedgetIdentifier()andisMandatory()via a sharedGuardrailIdentityparent; an out-of-tree guardrail must implement both. - Specialized services through the shared pipeline (ADR-096 / 097 / 098) —
AbstractSpecializedServicegained requiredMiddlewarePipelineandInputGuardrailScreenerconstructor parameters;MiddlewarePipeline::run()/ProviderMiddlewareInterface::handle()drop the separateLlmConfigurationargument (it now travels onProviderCallContext). - Rate-limit exception (ADR-095) — specialized services throw
ServiceQuotaExceededExceptionon HTTP 429 (a catch on theSpecializedServiceExceptionbase is unaffected). - Per-configuration tool gate in
ToolLoopService(ADR-093) — every consumer ofToolLoopServiceInterfaceis now subject to the skills' allow-list ∩allowed_tool_groups, not only the playground. - Runtime lifecycle service (ADR-101) —
ToolPlaygroundController's constructor takes the runtime;AgentRunPersister::resumeHandle()returns?AgentRunHandle;AgentRunRepositoryInterfacegainedmaxEventSequence()andsuspendRun()returnsbool. - Schema —
tx_nrllm_ai_session_messagegains a UNIQUE key on(session, sequence)andtx_nrllm_ai_sessiona UNIQUE key onuuid; an installation with pre-existing colliding rows must dedupe before the database analyzer can apply the index.
Full changelog
This release also lands the queued agent-runtime work (ADR-092 … ADR-116) and the earlier retention/guardrail/specialized-pipeline changes. See the complete Added / Changed / Fixed breakdown in CHANGELOG.md → 0.24.0.
Merged PRs in this release: #492–#518.
Merged pull requests
All pull requests in this release (#492–#518)
- chore(deps): update dependency sentence-transformers to v5.6.1 (#509)
- fix(deps): update dependency netresearch/nr-vault to ^0.10.1 || ^0.11.0 || ^0.12.0 (#511)
- docs(adr): central tooling authority — nr_llm owns builtin + MCP tools (#497)
- chore(release): 0.24.0 (#518)
- refactor(agent): encrypt agent state via nr-vault EncryptionService (P0 #4 follow-up) (#517)
- feat(tool)!: enforce tool data-class gate by default for new installs (P0 #3, slice 3b) (#516)
- feat(agent): encrypt queued and suspended agent-run state at rest (P0 #4) (#515)
- fix(tool)!: fail-closed tool data-class enforcement switch (P0 #3, slice 3a) (#514)
- feat(agent): queue delivery idempotency — tool effects + in-flight write fence (P0 #2) (#513)
- feat(agent)!: gate service accounts by declared scopes, fail-closed (P0 #1, slice 1d) (#512)
- refactor(agent)!: require an actor for run approve/submitInput/cancel/status/events (P0 #1, slice 1c) (#510)
- refactor(tool)!: authorise tools from an explicit actor, not ambient BE_USER (P0 #1, slice 1b) (#508)
- refactor(agent)!: carry the full AiActorContext through a queued run (P0 #1, slice 1a) (#507)
- fix(agent): ownership-guard the terminal settle so a reclaimed run is never clobbered (#506)
- fix(agent): heartbeat lease loss on MySQL no-op UPDATE + unbounded purge SELECT (#505)
- docs(administration): add Agent Runs admin guide (#504)
- build(phpstan): gate argument.type & varTag.nativeType on production code (#503)
- fix(agent): fail-closed on a stale-run wake-up dispatch failure + release-readiness hardening (#502)
- test(e2e): seed waiting runs to axe the Agent Runs approve/input forms (ADR-109) (#501)
- test(e2e): axe accessibility coverage for the Agent Runs module (ADR-109) (#500)
- feat(backend): Agent Runs approvals inbox (ADR-109) (#499)
- feat(agent): typed ToolResult with run-only artifacts (ADR-108) (#498)
- feat(agent): context-window management for the tool loop (ADR-107) (#496)
- ci(pages): make the landing-page workflow a pure reusable caller (#495)
- feat(guardrail): per-configuration guardrail policies (ADR-106) (#494)
- feat(agent): typed user-input suspension — WAITING_FOR_INPUT (ADR-105) (#493)
- ci(pages): delegate Pages deploy to shared reusable (#492)
Installation
composer require netresearch/nr-llmPublication status
- TER: extensions.typo3.org/extension/nr_llm — 0.24.0 verified
- Packagist: packagist.org/packages/netresearch/nr-llm — 0.24.0 verified
- Documentation: docs.typo3.org/p/netresearch/nr-llm/0.24/en-us/ — render verified
Security
All release artifacts are signed with Sigstore keyless signing.
Verify signatures
cosign verify-blob \
--bundle nr-llm-0.24.0.zip.sigstore.json \
--certificate-identity-regexp "https://github.com/netresearch/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
nr-llm-0.24.0.zipVerify checksums
sha256sum -c checksums.txtSoftware Bill of Materials (SBOM)
SBOMs are provided in both SPDX and CycloneDX formats for supply chain transparency.