Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,35 @@ All three systems share the same mental model:

Memories are deduplicated at write time. Conflicting memories (same topic, different content) are automatically resolved — the newer one supersedes the older one.

### Time-based confidence decay

Stale memories don't sit at 0.5 forever. At recall time, confidence decays exponentially based on how recently the memory was created or last recalled:

```
decayedConfidence = storedConfidence × 0.5^(daysSince / 90)
```

A memory untouched for 90 days has its effective confidence halved. Recalling a memory resets its decay clock — actively used knowledge stays fresh. Stored confidence is never mutated by decay; only `confirm()` and `reject()` change the stored value.

### Agent attribution

Track which agent stored a memory with the optional `source` parameter:

```ts
await mem.remember('always use pnpm', { source: 'deploy-agent' })
```

### Anti-patterns (deja-local & deja-edge)

When a memory is rejected enough that its confidence drops below 0.15, it auto-inverts into an **anti-pattern** — a warning that actively surfaces during recall:

```
Before: "use eval for JSON parsing" (confidence: 0.05, type: "memory")
After: "KNOWN PITFALL: use eval for JSON parsing" (confidence: 0.5, type: "anti-pattern")
```

Negative knowledge is as valuable as positive knowledge. Anti-patterns participate in recall normally and warn agents away from known mistakes.

## Hosted service API

The hosted service adds features beyond basic memory:
Expand Down
63 changes: 63 additions & 0 deletions marketing/src/content/patterns/memory-hygiene.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,34 @@ Deja uses vector similarity to match memories. As the store grows, semantically

Memories that haven't been recalled gradually lose confidence, making room for fresher knowledge.

**deja-local and deja-edge now have built-in time-based decay.** No cron jobs, no manual scripts — decay is computed automatically at recall time using an exponential half-life formula:

```
decayedConfidence = storedConfidence × 0.5^(daysSince / 90)
```

- A memory untouched for 90 days has its effective confidence halved
- Recalling a memory resets its decay clock — actively used knowledge stays fresh
- Stored confidence is never mutated by decay; only `confirm()` and `reject()` change the stored value
- No background jobs or cron — decay is a pure read-side computation

```typescript
// deja-local: decay is automatic — just use recall() normally
import { createMemory } from 'deja-local'

const mem = createMemory({ path: './agent.db' })

// This memory will naturally decay over time if not recalled
await mem.remember('always run migrations before deploying')

// 90 days later, this memory's effective confidence is halved in recall results
// But recalling it resets the decay clock:
const results = await mem.recall('deploying to staging')
// results[0].confidence is the stored value; the score reflects decay
```

For the **hosted service**, you can still run manual decay for more control:

```typescript
import { deja } from "deja-client";

Expand Down Expand Up @@ -305,6 +333,41 @@ crons = ["0 3 * * *"] # Daily at 3 AM UTC
| Human-taught memory | **Exempt** from decay | Human teachings are curated and intentional |
| Postmortem learning | **Slow decay** only | Incident knowledge stays relevant for months |

## Anti-Patterns: When Bad Memories Become Useful Warnings

In deja-local and deja-edge, heavily rejected memories don't just fade away — they transform into **anti-patterns** that actively warn agents.

When `reject()` drops a memory's confidence below 0.15:
1. The memory's type flips from `"memory"` to `"anti-pattern"`
2. Confidence resets to 0.5 (it's now a useful warning, not a failed memory)
3. Text is prefixed with `"KNOWN PITFALL: "`

```typescript
import { createMemory } from 'deja-local'

const mem = createMemory({ path: './agent.db' })

// Agent learns something wrong
const m = await mem.remember('use eval() to parse JSON strings')

// Other agents or humans reject it
await mem.reject(m.id) // 0.5 → 0.35
await mem.reject(m.id) // 0.35 → 0.2
await mem.reject(m.id) // 0.2 → 0.05 → auto-inverts!

// Now it's an anti-pattern that actively warns agents:
const list = mem.list()
// list[0].text = "KNOWN PITFALL: use eval() to parse JSON strings"
// list[0].type = "anti-pattern"
// list[0].confidence = 0.5

// Anti-patterns appear in recall results normally
const results = await mem.recall('parsing JSON')
// results[0].text = "KNOWN PITFALL: use eval() to parse JSON strings"
```

Anti-patterns are exempt from further inversion — they won't double-prefix. You can `confirm()` an anti-pattern to boost its confidence, making the warning more prominent.

## Monitoring Memory Health

```typescript
Expand Down
13 changes: 11 additions & 2 deletions packages/deja-edge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,16 @@ Your wrangler config needs a DO with SQLite:

All methods are synchronous — no async needed, no network calls. Everything runs in the DO's SQLite.

### `remember(text)`
### `remember(text, options?)`

Store a memory.

```ts
memory.remember('Redis must be running before starting the API server')
memory.remember('Use pnpm, not npm')

// With agent attribution
memory.remember('always check wrangler.toml', { source: 'deploy-agent' })
```

Dedup: near-identical text is detected and skipped.
Expand Down Expand Up @@ -112,12 +115,18 @@ Routes: `POST /remember`, `POST /recall`, `POST /confirm/:id`, `POST /reject/:id

## How it works

**Search**: SQLite FTS5 with Porter stemming tokenizer. Queries are decomposed into keywords, matched with `OR`, and ranked by BM25. Scores are normalized to 0-1 and blended with confidence (70% relevance, 30% confidence).
**Search**: SQLite FTS5 with Porter stemming tokenizer. Queries are decomposed into keywords, matched with `OR`, and ranked by BM25. Scores are normalized to 0-1 and blended with decayed confidence (70% relevance, 30% confidence).

**Time-based decay**: Confidence decays exponentially at recall time (half-life: 90 days). Memories that are recalled frequently stay fresh — each recall resets the decay clock. Stored confidence is only changed by `confirm()` and `reject()`.

**Dedup**: Trigram Jaccard similarity. Memories above 0.85 similarity are considered duplicates.

**Conflict resolution**: Memories between 0.5-0.85 similarity are about the same topic but say different things. The old memory's confidence drops to 30%, the new one takes priority.

**Anti-patterns**: When `reject()` drops a memory's confidence below 0.15, it auto-inverts into an anti-pattern — prefixed with "KNOWN PITFALL: ", confidence resets to 0.5, and it surfaces in recall as a warning. Negative knowledge actively warns agents away from known mistakes.

**Agent attribution**: Pass `{ source: 'agent-name' }` to `remember()` to track which agent stored a memory.

## Configuration

```ts
Expand Down
Loading
Loading