pi-hermes-memory 0.6.0 → 0.6.1
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
CHANGED
|
@@ -38,6 +38,7 @@ pi install npm:pi-hermes-memory
|
|
|
38
38
|
|---|---|
|
|
39
39
|
| 🔍 **Session Search** | Search across all past conversations via SQLite FTS5 |
|
|
40
40
|
| 🧠 **Persistent Memory** | Facts, preferences, lessons saved to markdown files |
|
|
41
|
+
| ⚠️ **Failure Memory** | Learn from failures — stores what didn't work and why |
|
|
41
42
|
| 📚 **Procedural Skills** | The agent saves *how* it solved problems as reusable docs |
|
|
42
43
|
| ⚡ **Background Learning** | Every 10 turns (or 15 tool calls) the agent reviews and saves |
|
|
43
44
|
| 🔧 **Correction Detection** | When you correct the agent, it saves immediately |
|
|
@@ -124,9 +125,51 @@ System Prompt
|
|
|
124
125
|
│ • tests use node:test with tsx │
|
|
125
126
|
│ ═══ END MEMORY ═══ │
|
|
126
127
|
│ </memory-context> │
|
|
128
|
+
│ │
|
|
129
|
+
│ <memory-context> │
|
|
130
|
+
│ RECENT FAILURES & LESSONS (learn from): │
|
|
131
|
+
│ • [correction] Use pnpm, not npm │
|
|
132
|
+
│ • [failure] Tried localStorage — XSS │
|
|
133
|
+
│ • [insight] Auth0 handles refresh tokens│
|
|
134
|
+
│ ═══ END MEMORY ═══ │
|
|
135
|
+
│ </memory-context> │
|
|
127
136
|
└─────────────────────────────────────────┘
|
|
128
137
|
```
|
|
129
138
|
|
|
139
|
+
## Failure Memory
|
|
140
|
+
|
|
141
|
+
The agent learns from failures, corrections, and insights — just like humans do.
|
|
142
|
+
|
|
143
|
+
### Memory Categories
|
|
144
|
+
|
|
145
|
+
| Category | What it stores | Example |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `failure` | What didn't work and why | "Tried localStorage for tokens — XSS vulnerability" |
|
|
148
|
+
| `correction` | User corrections | "Use pnpm, not npm" |
|
|
149
|
+
| `insight` | Learnings from experience | "Auth0 SDK handles refresh tokens automatically" |
|
|
150
|
+
| `preference` | User preferences | "Prefers dark theme" |
|
|
151
|
+
| `convention` | Project conventions | "Monorepo uses turborepo" |
|
|
152
|
+
| `tool-quirk` | Tool-specific knowledge | "CI needs --frozen-lockfile" |
|
|
153
|
+
|
|
154
|
+
### How It Works
|
|
155
|
+
|
|
156
|
+
1. **Auto-detection**: Background review extracts failures from conversations
|
|
157
|
+
2. **Correction capture**: When you correct the agent, it saves what went wrong
|
|
158
|
+
3. **System prompt injection**: Recent failures (last 7 days) are injected at session start
|
|
159
|
+
4. **Searchable**: Use `memory_search("auth", category: "failure")` to find past failures
|
|
160
|
+
|
|
161
|
+
### Example
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
User: No, use pnpm not npm
|
|
165
|
+
Agent: [saves correction memory]
|
|
166
|
+
|
|
167
|
+
Next session:
|
|
168
|
+
Agent: "I remember you prefer pnpm over npm. Let me use that."
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
The agent learns from its mistakes so you don't have to repeat yourself.
|
|
172
|
+
|
|
130
173
|
Memory blocks are wrapped in `<memory-context>` XML tags with a guard note ("NOT new user input") to prevent the LLM from treating stored facts as instructions.
|
|
131
174
|
|
|
132
175
|
## Usage
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-hermes-memory",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "🧠 Persistent memory + 🔍 session search + 🛡️ secret scanning for Pi. SQLite FTS5 search across every conversation, auto-consolidation, memory aging, procedural skills. 272 tests. Ported from Hermes agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -15,7 +15,7 @@ import type { ConsolidationResult } from "../types.js";
|
|
|
15
15
|
export async function triggerConsolidation(
|
|
16
16
|
pi: ExtensionAPI,
|
|
17
17
|
store: MemoryStore,
|
|
18
|
-
target: "memory" | "user",
|
|
18
|
+
target: "memory" | "user" | "failure",
|
|
19
19
|
signal?: AbortSignal,
|
|
20
20
|
): Promise<ConsolidationResult> {
|
|
21
21
|
const entries =
|
|
@@ -29,7 +29,7 @@ export class MemoryStore {
|
|
|
29
29
|
private userEntries: string[] = [];
|
|
30
30
|
private failureEntries: string[] = [];
|
|
31
31
|
private snapshot: MemorySnapshot = { memory: "", user: "" };
|
|
32
|
-
private consolidator: ((target: "memory" | "user", signal?: AbortSignal) => Promise<ConsolidationResult>) | null = null;
|
|
32
|
+
private consolidator: ((target: "memory" | "user" | "failure", signal?: AbortSignal) => Promise<ConsolidationResult>) | null = null;
|
|
33
33
|
|
|
34
34
|
constructor(private config: MemoryConfig) {}
|
|
35
35
|
|
|
@@ -37,7 +37,7 @@ export class MemoryStore {
|
|
|
37
37
|
* Inject a consolidation function (avoids circular imports).
|
|
38
38
|
* Called from index.ts after both store and pi are available.
|
|
39
39
|
*/
|
|
40
|
-
setConsolidator(fn: (target: "memory" | "user", signal?: AbortSignal) => Promise<ConsolidationResult>): void {
|
|
40
|
+
setConsolidator(fn: (target: "memory" | "user" | "failure", signal?: AbortSignal) => Promise<ConsolidationResult>): void {
|
|
41
41
|
this.consolidator = fn;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -100,7 +100,7 @@ export class MemoryStore {
|
|
|
100
100
|
|
|
101
101
|
// ─── CRUD ───
|
|
102
102
|
|
|
103
|
-
async add(target: "memory" | "user", content: string, signal?: AbortSignal): Promise<MemoryResult> {
|
|
103
|
+
async add(target: "memory" | "user" | "failure", content: string, signal?: AbortSignal): Promise<MemoryResult> {
|
|
104
104
|
return this._add(target, content, signal);
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -202,7 +202,7 @@ export class MemoryStore {
|
|
|
202
202
|
return this.successResponse(target, "Entry added.");
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
async replace(target: "memory" | "user", oldText: string, newContent: string): Promise<MemoryResult> {
|
|
205
|
+
async replace(target: "memory" | "user" | "failure", oldText: string, newContent: string): Promise<MemoryResult> {
|
|
206
206
|
oldText = oldText.trim();
|
|
207
207
|
newContent = newContent.trim();
|
|
208
208
|
if (!oldText) return { success: false, error: "old_text cannot be empty." };
|
|
@@ -248,7 +248,7 @@ export class MemoryStore {
|
|
|
248
248
|
return this.successResponse(target, "Entry replaced.");
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
async remove(target: "memory" | "user", oldText: string): Promise<MemoryResult> {
|
|
251
|
+
async remove(target: "memory" | "user" | "failure", oldText: string): Promise<MemoryResult> {
|
|
252
252
|
oldText = oldText.trim();
|
|
253
253
|
if (!oldText) return { success: false, error: "old_text cannot be empty." };
|
|
254
254
|
|
|
File without changes
|
|
File without changes
|