Some checks failed
CI / install-check (push) Has been cancelled
CI / checks (bunx tsc -p tsconfig.json --noEmit false, bun, build) (push) Has been cancelled
CI / checks (pnpm build && pnpm lint, node, lint) (push) Has been cancelled
CI / checks (pnpm canvas:a2ui:bundle && bunx vitest run, bun, test) (push) Has been cancelled
CI / checks (pnpm canvas:a2ui:bundle && pnpm test, node, test) (push) Has been cancelled
CI / checks (pnpm format, node, format) (push) Has been cancelled
CI / checks (pnpm protocol:check, node, protocol) (push) Has been cancelled
CI / checks (pnpm tsgo, node, tsgo) (push) Has been cancelled
CI / secrets (push) Has been cancelled
CI / checks-windows (pnpm build && pnpm lint, node, build & lint) (push) Has been cancelled
CI / checks-windows (pnpm canvas:a2ui:bundle && pnpm test, node, test) (push) Has been cancelled
CI / checks-windows (pnpm protocol:check, node, protocol) (push) Has been cancelled
CI / checks-macos (pnpm test, test) (push) Has been cancelled
CI / macos-app (set -euo pipefail
for attempt in 1 2 3; do
if swift build --package-path apps/macos --configuration release; then
exit 0
fi
echo "swift build failed (attempt $attempt/3). Retrying…"
sleep $((attempt * 20))
done
exit 1
, build) (push) Has been cancelled
CI / macos-app (set -euo pipefail
for attempt in 1 2 3; do
if swift test --package-path apps/macos --parallel --enable-code-coverage --show-codecov-path; then
exit 0
fi
echo "swift test failed (attempt $attempt/3). Retrying…"
sleep $((attempt … (push) Has been cancelled
CI / macos-app (swiftlint --config .swiftlint.yml
swiftformat --lint apps/macos/Sources --config .swiftformat
, lint) (push) Has been cancelled
CI / ios (push) Has been cancelled
CI / android (./gradlew --no-daemon :app:assembleDebug, build) (push) Has been cancelled
CI / android (./gradlew --no-daemon :app:testDebugUnitTest, test) (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
- Add comprehensive docs/features/event-store.md - Add unit tests for event-store.ts - Add migration script for existing workspaces - Update CHANGELOG with new features Part of Event-Sourced Memory feature (RFC-001)
248 lines
6.1 KiB
Markdown
248 lines
6.1 KiB
Markdown
# Event Store Integration
|
|
|
|
OpenClaw can persist all agent events to NATS JetStream, enabling event-sourced memory, audit trails, and multi-agent knowledge sharing.
|
|
|
|
## Overview
|
|
|
|
When enabled, every interaction becomes an immutable event:
|
|
- User/assistant messages
|
|
- Tool calls and results
|
|
- Session lifecycle (start/end)
|
|
- Custom events from extensions
|
|
|
|
Events are stored in NATS JetStream and can be:
|
|
- Queried for context building
|
|
- Replayed for debugging
|
|
- Shared across agents (with isolation)
|
|
- Used for continuous learning
|
|
|
|
## Configuration
|
|
|
|
Add to your `config.yml`:
|
|
|
|
```yaml
|
|
gateway:
|
|
eventStore:
|
|
enabled: true
|
|
url: nats://localhost:4222
|
|
streamName: openclaw-events
|
|
subjectPrefix: openclaw.events
|
|
```
|
|
|
|
### Full Options
|
|
|
|
```yaml
|
|
gateway:
|
|
eventStore:
|
|
enabled: true # Enable event publishing
|
|
url: nats://user:pass@localhost:4222 # NATS connection URL
|
|
streamName: openclaw-events # JetStream stream name
|
|
subjectPrefix: openclaw.events # Subject prefix for events
|
|
|
|
# Multi-agent configuration (optional)
|
|
agents:
|
|
my-agent:
|
|
url: nats://agent:pass@localhost:4222
|
|
streamName: events-my-agent
|
|
subjectPrefix: openclaw.events.my-agent
|
|
```
|
|
|
|
## Event Types
|
|
|
|
| Type | Description |
|
|
|------|-------------|
|
|
| `conversation.message.out` | Messages sent to/from the model |
|
|
| `conversation.tool_call` | Tool invocations |
|
|
| `conversation.tool_result` | Tool results |
|
|
| `lifecycle.start` | Session started |
|
|
| `lifecycle.end` | Session ended |
|
|
|
|
## Event Schema
|
|
|
|
```typescript
|
|
interface OpenClawEvent {
|
|
id: string; // Unique event ID
|
|
timestamp: number; // Unix milliseconds
|
|
agent: string; // Agent identifier
|
|
session: string; // Session key
|
|
type: string; // Event type
|
|
visibility: string; // 'internal' | 'public'
|
|
payload: {
|
|
runId: string; // Current run ID
|
|
stream: string; // Event stream type
|
|
data: any; // Event-specific data
|
|
sessionKey: string;
|
|
seq: number; // Sequence in run
|
|
ts: number;
|
|
};
|
|
meta: {
|
|
runId: string;
|
|
seq: number;
|
|
model?: string;
|
|
channel?: string;
|
|
};
|
|
}
|
|
```
|
|
|
|
## Context Injection
|
|
|
|
When event store is enabled, OpenClaw automatically:
|
|
|
|
1. Queries recent events on session start
|
|
2. Extracts conversation history and topics
|
|
3. Injects context into the system prompt
|
|
|
|
This gives the agent memory of recent interactions without manual file management.
|
|
|
|
### Context Format
|
|
|
|
The injected context includes:
|
|
- Recent conversation snippets (deduplicated)
|
|
- Active topics mentioned
|
|
- Event count and timeframe
|
|
|
|
## Multi-Agent Isolation
|
|
|
|
For multi-agent setups, each agent can have its own stream:
|
|
|
|
```yaml
|
|
gateway:
|
|
eventStore:
|
|
enabled: true
|
|
url: nats://main:password@localhost:4222
|
|
streamName: openclaw-events
|
|
subjectPrefix: openclaw.events.main
|
|
|
|
agents:
|
|
assistant-one:
|
|
url: nats://assistant1:pass@localhost:4222
|
|
streamName: events-assistant-one
|
|
subjectPrefix: openclaw.events.assistant-one
|
|
assistant-two:
|
|
url: nats://assistant2:pass@localhost:4222
|
|
streamName: events-assistant-two
|
|
subjectPrefix: openclaw.events.assistant-two
|
|
```
|
|
|
|
Combined with NATS account permissions, this ensures agents can only read their own events.
|
|
|
|
## NATS Setup
|
|
|
|
### Quick Start (Docker)
|
|
|
|
```bash
|
|
docker run -d --name nats \
|
|
-p 4222:4222 \
|
|
-v nats-data:/data \
|
|
nats:latest \
|
|
-js -sd /data
|
|
```
|
|
|
|
### Create Stream
|
|
|
|
```bash
|
|
nats stream add openclaw-events \
|
|
--subjects "openclaw.events.>" \
|
|
--storage file \
|
|
--retention limits \
|
|
--max-age 90d
|
|
```
|
|
|
|
### Secure Setup (Multi-Agent)
|
|
|
|
See [NATS Security Documentation](https://docs.nats.io/running-a-nats-service/configuration/securing_nats) for setting up accounts and permissions.
|
|
|
|
Example secure config:
|
|
```
|
|
accounts {
|
|
AGENTS: {
|
|
jetstream: enabled
|
|
users: [
|
|
{ user: main, password: "xxx", permissions: { publish: [">"], subscribe: [">"] } },
|
|
{ user: agent1, password: "xxx", permissions: {
|
|
publish: ["openclaw.events.agent1.>", "$JS.API.>", "_INBOX.>"],
|
|
subscribe: ["openclaw.events.agent1.>", "_INBOX.>", "$JS.API.>"]
|
|
}}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
## Migration
|
|
|
|
To migrate existing memory files to the event store:
|
|
|
|
```bash
|
|
# Install dependencies
|
|
npm install nats
|
|
|
|
# Run migration
|
|
node scripts/migrate-to-eventstore.mjs
|
|
```
|
|
|
|
The migration script imports:
|
|
- Daily notes (`memory/*.md`)
|
|
- Long-term memory (`MEMORY.md`)
|
|
- Knowledge graph entries (`life/areas/`)
|
|
|
|
## Querying Events
|
|
|
|
### Via NATS CLI
|
|
|
|
```bash
|
|
# List streams
|
|
nats stream ls
|
|
|
|
# Get stream info
|
|
nats stream info openclaw-events
|
|
|
|
# Read recent events
|
|
nats consumer add openclaw-events reader --deliver last --ack none
|
|
nats consumer next openclaw-events reader --count 10
|
|
```
|
|
|
|
### Programmatically
|
|
|
|
```typescript
|
|
import { connect, StringCodec } from 'nats';
|
|
|
|
const nc = await connect({ servers: 'localhost:4222' });
|
|
const js = nc.jetstream();
|
|
const jsm = await nc.jetstreamManager();
|
|
|
|
// Get last 100 events
|
|
const info = await jsm.streams.info('openclaw-events');
|
|
for (let seq = info.state.last_seq - 100; seq <= info.state.last_seq; seq++) {
|
|
const msg = await jsm.streams.getMessage('openclaw-events', { seq });
|
|
const event = JSON.parse(StringCodec().decode(msg.data));
|
|
console.log(event.type, event.timestamp);
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
1. **Retention Policy**: Set appropriate max-age for your use case (default: 90 days)
|
|
2. **Stream per Agent**: Use separate streams for agent isolation
|
|
3. **Backup**: Configure NATS replication or backup JetStream data directory
|
|
4. **Monitoring**: Use NATS monitoring endpoints to track stream health
|
|
|
|
## Troubleshooting
|
|
|
|
### Events not appearing
|
|
|
|
1. Check NATS connection: `nats server ping`
|
|
2. Verify stream exists: `nats stream ls`
|
|
3. Check OpenClaw logs for connection errors
|
|
4. Ensure `eventStore.enabled: true` in config
|
|
|
|
### Context not loading
|
|
|
|
1. Verify events exist in stream
|
|
2. Check NATS credentials have read permission
|
|
3. Look for errors in OpenClaw startup logs
|
|
|
|
### Performance issues
|
|
|
|
1. Limit event retention with `--max-age`
|
|
2. Use separate streams for high-volume agents
|
|
3. Consider NATS clustering for scale
|