# FlowDrop Memory

> Scoped, pluggable memory storage for FlowDrop workflows and AI agents.

## Overview

The `flowdrop_memory` module provides a key-value memory system that workflow nodes can use to persist and share data across executions. Memory is stored in named keys within a **scope** — a boundary that determines who can read and write the value.

| Scope | Access boundary |
|-------|----------------|
| `global` | Accessible from any workflow, session, or pipeline |
| `workflow` | Shared across all pipelines and sessions within the same workflow definition |
| `pipeline` | Shared across all nodes within a single pipeline execution |
| `execution` | Isolated to a single workflow execution run |
| `session` | Shared within a session (useful for multi-turn conversations) |

The active storage backend is configurable per-scope. Three backends are included: in-process static memory (ephemeral), Drupal cache bins (TTL-aware), and database-backed entity storage (durable).

!!! note "Experimental"
    This module is marked `lifecycle: experimental`. The API may change in minor releases. See the [BC Policy](../reference/api/bc-policy.md).

## Dependencies

- [flowdrop](flowdrop.md)
- [flowdrop_node_type](flowdrop_node_type.md)

## Configuration

### Admin Pages

| Path | Description |
|------|-------------|
| `/admin/flowdrop/memory/settings` | Configure the active backend per scope |

### Permissions

Memory settings are governed by the core `administer flowdrop` permission.

## Tips and Tricks

### Choosing a Backend

| Use Case | Recommended Backend |
|----------|---------------------|
| Temporary scratch space within a single request | `static` |
| Cross-request sharing with optional expiry | `cached` |
| Durable state that survives cache clears | `entity` |

### Context-Aware vs Raw Nodes

The `memory_read` and `memory_write` nodes implement `ExecutionContextAwareInterface`. The runtime automatically injects the execution context before the node runs, allowing scope IDs to be derived without manual wiring:

- `scope=workflow` → workflow ID
- `scope=pipeline` → pipeline ID
- `scope=execution` → execution ID
- `scope=session` → `metadata['session_id']`

Use `memory_read_raw` / `memory_write_raw` when you need to target a specific scope ID explicitly — for example, reading memory written by a different workflow.

### Using Memory for Agent State

Memory nodes are particularly useful in AI agent workflows to maintain state between turns:

```
[Chat Input] → [memory_read (scope=session, key="history")]
             → [Chat Model]
             → [memory_write (scope=session, key="history")]
             → [Chat Output]
```

## Developer API

### Services

| Service ID | Class | Description |
|-----------|-------|-------------|
| `flowdrop_memory.manager` | `MemoryManager` | Central service for all memory operations |
| `flowdrop_memory.backend_plugin_manager` | `MemoryBackendPluginManager` | Discovers and instantiates backend plugins |

#### MemoryManager

```php
$manager = \Drupal::service('flowdrop_memory.manager');

$manager->set($scope, $scopeId, $key, $value, ?int $ttl = NULL);
$value  = $manager->get($scope, $scopeId, $key, $default = NULL);
$exists = $manager->has($scope, $scopeId, $key);
$manager->delete($scope, $scopeId, $key);
$manager->clear($scope, $scopeId);
```

### Entities

#### MemoryRecord (Content Entity)

Stores durable key-value records when the `entity` backend is active. Each record is uniquely identified by `(scope, scope_id, key)`.

### Node Processors

| Plugin ID | Context-Aware | Description |
|-----------|:---:|-------------|
| `memory_read` | ✅ | Read a value; scope ID auto-resolved from execution context |
| `memory_write` | ✅ | Write a value; scope ID auto-resolved from execution context |
| `memory_read_raw` | ❌ | Read with an explicit scope ID |
| `memory_write_raw` | ❌ | Write with an explicit scope ID |

### Custom Backends

Implement `MemoryBackendInterface` and annotate with `#[MemoryBackend]`:

```php
use Drupal\flowdrop_memory\Attribute\MemoryBackend;
use Drupal\flowdrop_memory\Plugin\MemoryBackend\MemoryBackendInterface;

#[MemoryBackend(id: 'my_backend', label: new TranslatableMarkup('My Backend'))]
class MyMemoryBackend implements MemoryBackendInterface {
  // implement get(), set(), has(), delete(), clear()
}
```

## References

- [Node Reference — Memory](../guide/nodes/memory.md)
- [flowdrop_stategraph](flowdrop_stategraph.md) — stateful execution with a related state store pattern
- [flowdrop_session](flowdrop_session.md) — session context used by `scope=session`
