@agent-pulse/elizaos-plugin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +309 -0
- package/dist/index.cjs +1794 -0
- package/dist/index.js +1765 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# @openclaw/eliza-plugin-pulse
|
|
2
|
+
|
|
3
|
+
ElizaOS plugin for the [Agent Pulse](https://agentpulse.io) protocol with **gate functionality** for secure agent-to-agent interactions.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Agent Pulse is a decentralized liveness protocol where agents prove they're alive by transferring PULSE tokens to a signal sink. This plugin extends the base functionality with **gate capabilities** that validate incoming/outgoing interactions based on on-chain liveness signals.
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- ✅ **Standard Pulse Actions**: Send pulses, check status, monitor protocol health
|
|
12
|
+
- 🔒 **Inbound Gate**: Validates incoming messages from external agents before processing
|
|
13
|
+
- 🚪 **Outbound Gate**: Checks target agent status before sending responses
|
|
14
|
+
- 📊 **v2 Analytics**: Reliability metrics, liveness proofs, global stats, peer correlation
|
|
15
|
+
- ⚙️ **Multiple Modes**: Strict, permissive, and audit modes for different security needs
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @openclaw/eliza-plugin-pulse
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
### 1. Add to Your Character File
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"name": "MyAgent",
|
|
30
|
+
"plugins": ["@openclaw/eliza-plugin-pulse"],
|
|
31
|
+
"settings": {
|
|
32
|
+
"pulse": {
|
|
33
|
+
"gate": {
|
|
34
|
+
"enabled": true,
|
|
35
|
+
"mode": "strict",
|
|
36
|
+
"threshold": "24h"
|
|
37
|
+
},
|
|
38
|
+
"contractAddress": "0xe61C615743A02983A46aFF66Db035297e8a43846",
|
|
39
|
+
"chainId": 84532
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Environment Variables (Optional)
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
AGENT_PULSE_RPC_URL=https://sepolia.base.org
|
|
49
|
+
AGENT_PULSE_API_URL=https://api.agentpulse.io
|
|
50
|
+
AGENT_PULSE_TOKEN_ADDRESS=0x21111B39A502335aC7e45c4574Dd083A69258b07
|
|
51
|
+
AGENT_PULSE_REGISTRY_ADDRESS=0xe61C615743A02983A46aFF66Db035297e8a43846
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Gate Configuration
|
|
55
|
+
|
|
56
|
+
The gate reads configuration from `character.settings.pulse`:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"settings": {
|
|
61
|
+
"pulse": {
|
|
62
|
+
"gate": {
|
|
63
|
+
"enabled": true, // Enable/disable the gate
|
|
64
|
+
"mode": "strict", // "strict" | "permissive" | "audit"
|
|
65
|
+
"threshold": "24h" // Max age for considering agent alive
|
|
66
|
+
},
|
|
67
|
+
"contractAddress": "0xe61C615743A02983A46aFF66Db035297e8a43846",
|
|
68
|
+
"chainId": 84532,
|
|
69
|
+
"rpcUrl": "https://sepolia.base.org" // Optional override
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Gate Modes
|
|
76
|
+
|
|
77
|
+
| Mode | Behavior | Use Case |
|
|
78
|
+
|------|----------|----------|
|
|
79
|
+
| `strict` | Block messages from agents that fail `isAlive()` check | High-security environments |
|
|
80
|
+
| `permissive` | Allow all messages, flag suspicious ones with warnings | Balanced security/UX |
|
|
81
|
+
| `audit` | Always allow, log all checks (dry-run) | Testing and monitoring |
|
|
82
|
+
|
|
83
|
+
### Threshold Format
|
|
84
|
+
|
|
85
|
+
The threshold accepts ISO 8601 duration formats:
|
|
86
|
+
|
|
87
|
+
- `"24h"` - 24 hours
|
|
88
|
+
- `"1d"` - 1 day
|
|
89
|
+
- `"12h"` - 12 hours
|
|
90
|
+
- `"PT6H"` - 6 hours (ISO format)
|
|
91
|
+
|
|
92
|
+
## How the Gate Works
|
|
93
|
+
|
|
94
|
+
### Inbound Gate (Evaluator)
|
|
95
|
+
|
|
96
|
+
Runs **before all other evaluators** for every message:
|
|
97
|
+
|
|
98
|
+
1. **Identity Extraction**: Extracts sender's Ethereum address from:
|
|
99
|
+
- Message text (e.g., "I'm agent 0x1234...")
|
|
100
|
+
- User metadata
|
|
101
|
+
- Sender ID (if it looks like an address)
|
|
102
|
+
|
|
103
|
+
2. **Agent Detection**: Determines if sender is likely an agent using heuristics:
|
|
104
|
+
- Contains Ethereum addresses
|
|
105
|
+
- Agent-specific keywords (pulse, stake, smart contract)
|
|
106
|
+
- Agent-like metadata markers
|
|
107
|
+
|
|
108
|
+
3. **IsAlive Check**: Calls Pulse API to verify:
|
|
109
|
+
- Is the agent registered?
|
|
110
|
+
- When was the last pulse?
|
|
111
|
+
- Is it within the threshold?
|
|
112
|
+
|
|
113
|
+
4. **Decision**: Based on mode:
|
|
114
|
+
- `strict`: Block if not alive
|
|
115
|
+
- `permissive`: Allow but flag
|
|
116
|
+
- `audit`: Allow and log
|
|
117
|
+
|
|
118
|
+
### Outbound Gate (Action Wrapper)
|
|
119
|
+
|
|
120
|
+
Wraps all action handlers to check target agents:
|
|
121
|
+
|
|
122
|
+
1. **Target Extraction**: Identifies recipient from:
|
|
123
|
+
- Action options (`targetAddress`)
|
|
124
|
+
- State from inbound gate (replying to an agent)
|
|
125
|
+
- Message content
|
|
126
|
+
|
|
127
|
+
2. **Status Check**: Verifies target's liveness
|
|
128
|
+
|
|
129
|
+
3. **Action Control**: Blocks or proceeds based on decision
|
|
130
|
+
|
|
131
|
+
## Edge Cases
|
|
132
|
+
|
|
133
|
+
The gate handles these scenarios gracefully:
|
|
134
|
+
|
|
135
|
+
| Scenario | Behavior |
|
|
136
|
+
|----------|----------|
|
|
137
|
+
| **No pulse settings** | Gate is no-op (disabled), all interactions allowed |
|
|
138
|
+
| **RPC unreachable** | Degrades per mode: strict=block, permissive/audit=allow |
|
|
139
|
+
| **Non-agent user** | Skips gate entirely (humans pass through) |
|
|
140
|
+
| **No identity found** | strict=block, others=skip |
|
|
141
|
+
| **Agent never pulsed** | Treated as not alive (fails check) |
|
|
142
|
+
| **Cache expired** | Re-checks status with 1-minute caching |
|
|
143
|
+
|
|
144
|
+
## Example Character
|
|
145
|
+
|
|
146
|
+
See [example-gated-character.json](./example-gated-character.json) for a complete example of an agent configured with:
|
|
147
|
+
|
|
148
|
+
- Strict gate mode enabled
|
|
149
|
+
- 24-hour liveness threshold
|
|
150
|
+
- Security-focused personality
|
|
151
|
+
- Helpful responses for verified agents
|
|
152
|
+
|
|
153
|
+
## Actions
|
|
154
|
+
|
|
155
|
+
### SEND_PULSE
|
|
156
|
+
Send a liveness pulse to prove the agent is alive.
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
User: "Send a pulse for my agent"
|
|
160
|
+
Agent: "✅ Pulse sent successfully! Transaction: 0xabc... Streak: 5"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### GET_AGENT_STATUS
|
|
164
|
+
Get the current status of an agent.
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
User: "Check my agent status"
|
|
168
|
+
Agent: "**Agent Status: 0x742d...0bEb**
|
|
169
|
+
🟢 Alive
|
|
170
|
+
• Last Pulse: 2 hours ago
|
|
171
|
+
• Streak: 🔥 5 days
|
|
172
|
+
• Hazard Score: ✅ 0/100"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### GET_RELIABILITY (v2 - Paid)
|
|
176
|
+
Get comprehensive reliability metrics.
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
User: "Check reliability"
|
|
180
|
+
Agent: "Agent reliability: 92.3%
|
|
181
|
+
Uptime: 99.1%
|
|
182
|
+
Jitter: 0.08
|
|
183
|
+
Hazard Rate: 0.02"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
**Price:** $0.01 USDC
|
|
187
|
+
|
|
188
|
+
### GET_LIVENESS_PROOF (v2 - Paid)
|
|
189
|
+
Get a cryptographically signed proof of liveness.
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
User: "Get liveness proof"
|
|
193
|
+
Agent: "✅ Alive | Proof: eyJhbG..."
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Price:** $0.005 USDC
|
|
197
|
+
|
|
198
|
+
### GET_GLOBAL_STATS (v2 - Paid)
|
|
199
|
+
Get network-wide aggregate statistics.
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
User: "Show network stats"
|
|
203
|
+
Agent: "Active Agents: 1,500
|
|
204
|
+
Average Streak: 30.5 days
|
|
205
|
+
Network Health: ✅ Healthy"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Price:** $0.03 USDC
|
|
209
|
+
|
|
210
|
+
### GET_PEER_CORRELATION (v2 - Paid)
|
|
211
|
+
Find agents with correlated liveness patterns.
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
User: "Find similar agents"
|
|
215
|
+
Agent: "Correlation: 0.78
|
|
216
|
+
Similar agents: 2 found
|
|
217
|
+
Cluster: copywriters-west"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Price:** $0.02 USDC
|
|
221
|
+
|
|
222
|
+
## Providers
|
|
223
|
+
|
|
224
|
+
### PULSE_STATE
|
|
225
|
+
Provides current state from the Agent Pulse protocol:
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
Agent Pulse Protocol:
|
|
229
|
+
Protocol: ✅ HEALTHY | 1,234 agents
|
|
230
|
+
Agent: 🟢 Alive | 🔥 5 | 2h ago
|
|
231
|
+
TTL: 24h | Min pulse: 1 PULSE
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Programmatic Usage
|
|
235
|
+
|
|
236
|
+
### Check if an Agent is Alive
|
|
237
|
+
|
|
238
|
+
```typescript
|
|
239
|
+
import { isAlive, getPulseGateSettings } from "@openclaw/eliza-plugin-pulse";
|
|
240
|
+
|
|
241
|
+
const settings = getPulseGateSettings(runtime);
|
|
242
|
+
if (settings) {
|
|
243
|
+
const result = await isAlive(
|
|
244
|
+
"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
|
|
245
|
+
settings,
|
|
246
|
+
runtime
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
console.log(result.allowed); // true/false
|
|
250
|
+
console.log(result.reason); // Explanation if not allowed
|
|
251
|
+
console.log(result.status); // Full status object
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Extract Identity from Message
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { extractIdentity, isLikelyAgent } from "@openclaw/eliza-plugin-pulse";
|
|
259
|
+
|
|
260
|
+
const identity = extractIdentity(message, runtime);
|
|
261
|
+
if (identity.found) {
|
|
262
|
+
console.log(identity.address); // Ethereum address
|
|
263
|
+
console.log(identity.source); // "signature" | "claimed" | "inferred"
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const isAgent = isLikelyAgent(message, runtime);
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Manual Gate Check
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
import { makeGateDecision } from "@openclaw/eliza-plugin-pulse";
|
|
273
|
+
|
|
274
|
+
const decision = makeGateDecision(
|
|
275
|
+
"strict", // mode
|
|
276
|
+
checkResult, // GateCheckResult from isAlive()
|
|
277
|
+
identity // ExtractedIdentity
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
console.log(decision.allow); // true/false
|
|
281
|
+
console.log(decision.flag); // true/false
|
|
282
|
+
console.log(decision.log); // true/false
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Contract Addresses
|
|
286
|
+
|
|
287
|
+
**Base Sepolia (Chain ID: 84532)**
|
|
288
|
+
- PulseRegistry: `0xe61C615743A02983A46aFF66Db035297e8a43846`
|
|
289
|
+
- PulseToken: `0x21111B39A502335aC7e45c4574Dd083A69258b07`
|
|
290
|
+
|
|
291
|
+
## Development
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
# Install dependencies
|
|
295
|
+
npm install
|
|
296
|
+
|
|
297
|
+
# Build
|
|
298
|
+
npm run build
|
|
299
|
+
|
|
300
|
+
# Type check
|
|
301
|
+
npm run typecheck
|
|
302
|
+
|
|
303
|
+
# Watch mode
|
|
304
|
+
npm run dev
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT
|