v0.11.0 — Memory-as-tool DX: Recall/Remember tools
Memory-as-tool DX. First-class Recall/Remember tools agents can use mid-prompt, streaming-compatible. make:memory-tool generator and recipe book for common patterns. Purely additive — no breaking changes; existing apps upgrade with no required action.
Added
RecallandRememberagent memory tools (#128). NewBuiltByBerry\LaravelSwarm\Tools\RecallandTools\RememberimplementLaravel\Ai\Contracts\Tool, so an agent can read and write Swarm memory mid-prompt with no Swarm-specific code — drop them into anylaravel/aiagent'stools()array.Recallreads bykey,prefix, or wholescope;Rememberwrites akey/value. Both take ascopename (defaultrun, withswarmfor shared state) but resolve the scope id from the active run, never from the model, so an agent cannot address another run's or swarm's memory.Recallreads through the active swarm'sMemoryPropagationPolicy(it can only surface what the policy permits — no leaking from withheld scopes);Rememberwrites throughSwarmMemory::put()so theMemoryCapturePolicyredacts or drops at the write boundary, and reservedswarm:keys are rejected. Tool-driven writes are tagged with anoriginoftool:remember(plus the agent class when the tool is agent-bound) in the entry metadata, soMemoryWrittenaudit listeners can tell a model-initiated write apart from a framework write. Both work across all four topologies and nested runs, and degrade to a graceful "memory is not available" message outside a swarm run. The newConcerns\HasSwarmMemoryToolstrait plusswarm.memory.tools.{enabled,recall,remember}config provide optional, default-off, container-resolvable registration (bind a subclass to customise a tool or bind it to a specific agent foragent-scope addressing). See Swarm Memory.RecallandRememberwork inside streamed agent responses (#129). The memory tools now have end-to-end coverage inside$agent->stream(...). Because both implementLaravel\Ai\Contracts\Tool,laravel/aialready drives their invocation during a streamed turn, so the tool call and result surface in theStreamableSwarmResponseas ordinaryswarm_tool_call/swarm_tool_resultevents — no streaming-specific tool code. The sequential stream runner publishes the active run before invoking the final agent'sstream(), so a streamedRecallresolves its scope id from the ambient run (and sees what earlier steps wrote) and a streamedRememberwrite lands in memory before its result event is yielded and is visible to later steps. The snapshot mechanism captures the call's input and output: the runner holds eachToolCalluntil its matchingToolResultarrives, then appends a single paired entry to the step snapshot (a call left unmatched at stream end is recorded with a null result so replay can detect a partial run). Combined with persisted stream replay, a streamed run that used the memory tools replays byte-identically viaSwarmHistory::replay($runId). This release adds the integration and capture tests proving the path; no new runtime logic was required. See docs/memory.md.make:memory-toolgenerator (#130). Newphp artisan make:memory-tool {name}Artisan command scaffolds a custom Swarm memory tool underapp/Ai/Tools/, following the v0.8make:swarm:*generator pattern (#101 / #91) and theapp/Ai/starter-example conventions (#89). The generated class extends one of the shippedRecall/Remembertools (#128), so a custom tool inherits the same shape and safety guarantees — scope ids resolve from the active run (never from the model), reads honour the propagation policy, and writes flow through the capture policy.--scope=run|conversation|agent|swarmseeds the tool's defaultMemoryScope;--base=recall|rememberchooses the read- or write-tool shape (defaultrecall);--vectorscaffolds a semantic, vector-aware variant but only when thebuiltbyberry/laravel-swarm-memory-vectorcompanion is installed (detected via Composer'sInstalledVersions), erroring with an install hint otherwise;--forceoverwrites an existing file. Unknown--scope/--basevalues exit 1 with the valid options. Stubs are publishable viavendor:publish --tag=swarm-stubs(swarm.memory-tool.stub,swarm.memory-tool.vector.stub). See Generators.- Octane worker-reset flush for
ActiveRunContext(#171). Whenlaravel/octaneis installed,SwarmServiceProvidernow wires a listener on Octane'sOperationTerminatedcontract that callsActiveRunContext::flush()on every worker reset (request, task, and tick), so a stale run frame left by an abnormally-terminated run — a hard timeout or fatal that bypasses theenter()/exit()finally — is cleared eagerly instead of relying on the next run to shadow it. Opt-in by presence: the listener is registered only when Octane's contract is loadable, so non-Octane apps see zero behaviour change and the package never hard-depends on Octane.swarm:install:memorynow surfaces a confirmation note (and the manualconfig/octane.phpequivalent) when it detects Octane.
Documentation
- Memory-as-tool recipe book (#131). New docs/memory-recipes.md is the pattern companion to the Recall and Remember tools reference — the "here's how people actually use this" cookbook that anchors the memory contracts to real, copy-paste shipping patterns. Five worked recipes, each built on the tools' real extension hooks (so each is a
make:memory-tool-scaffoldable subclass) and stating a problem, code, and when-to-use guidance: per-user scoped recall (overrideRecall::visibleEntries()to filter toauth()->id()'s keys, so the model can't read across users), tenant-isolated memory (the honest mechanism — partition by swarm class or enforce a tenant-awareMemoryPropagationPolicy— reinforcing the existing warning thatswarmscope is shared across every tenant of a class), policy-enforced custom Recall (bake a scope/key allow-list into the tool viaresolveScope()+visibleEntries()so the read boundary survives prompt injection), recall + redact for compliance (bind aMemoryCapturePolicyreturningCaptureDecision::Redactso PII an agentRemembers never lands unredacted and laterRecalls read back[redacted]), and sub-agent with memory continuity (make theagentscope addressable by overridingagent(), giving a reusable sub-agent state that persists across runs). Cross-links the tool reference (docs/memory.md), the generator (docs/generators.md), and the capture-policy and compliance guides; registered in the docs index and cross-linked from docs/memory.md.
Testing
- Rollback schema tests assert table presence instead of
--stepcounts (#157).MemoriesSchemaTest,MemorySnapshotsSchemaTest, andRunIdForeignKeysTestno longer hard-codemigrate:rollback --step Ncounts — they roll back by locating each migration and asserting the table is actually gone, so adding a new migration no longer silently breaks an unrelated rollback assertion. Test-only change — nosrc/behavior change. - Coverage and mutation CI memory limit raised to 1G (#179). The
tests,nightly, andmutationworkflows run their coverage/mutation passes withmemory_limit=1Gso the growing suite — the v0.11 memory-tool topology matrix and streaming fixtures — no longer risks OOM under coverage instrumentation. CI-only change.