vektor-slipstream 1.3.6 → 1.3.7
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/CHANGELOG.md +139 -0
- package/audn-log.js +143 -0
- package/briefing.js +150 -0
- package/entity-resolver.js +298 -0
- package/errors.js +66 -0
- package/export-import.js +221 -0
- package/forget.js +148 -0
- package/inspect.js +199 -0
- package/migrate-137.js +105 -0
- package/namespace.js +186 -0
- package/package.json +39 -10
- package/pin.js +91 -0
- package/slipstream-core-extended.js +134 -0
- package/types/index.d.ts +269 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# VEKTOR v1.3.7 — Changelog
|
|
2
|
+
|
|
3
|
+
Released: 2026-04-05
|
|
4
|
+
|
|
5
|
+
## New features
|
|
6
|
+
|
|
7
|
+
### memory.forget(id)
|
|
8
|
+
Hard-deletes a memory and cascades to all graph edges. Throws if memory is pinned — must unpin first.
|
|
9
|
+
```js
|
|
10
|
+
await memory.forget('mem_abc123');
|
|
11
|
+
// → { deleted: true, edgesRemoved: 4 }
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
### memory.forgetWhere(query, opts)
|
|
15
|
+
Semantic bulk-delete. Preview with `dryRun: true` before committing.
|
|
16
|
+
```js
|
|
17
|
+
await memory.forgetWhere('Project Atlas', { dryRun: true });
|
|
18
|
+
await memory.forgetWhere('Project Atlas', { minScore: 0.9, limit: 5 });
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### memory.pin(id) / memory.unpin(id) / memory.listPinned()
|
|
22
|
+
Mark memories as permanent — REM cycle will never compress or delete them.
|
|
23
|
+
```js
|
|
24
|
+
const { id } = await memory.remember('User is allergic to peanuts');
|
|
25
|
+
await memory.pin(id);
|
|
26
|
+
await memory.listPinned(); // → all pinned memories
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### memory.inspect()
|
|
30
|
+
Full diagnostic snapshot — no more raw SQLite queries to debug state.
|
|
31
|
+
```js
|
|
32
|
+
const state = memory.inspect();
|
|
33
|
+
state.counts // → { memories: 247, pinned: 3, edges: 7180 }
|
|
34
|
+
state.rem // → { totalDreams: 11, compressionRatio: '0.06' }
|
|
35
|
+
state.graph.topNodes // → 5 most-connected memories
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### memory.auditLog(opts) / memory.auditStats()
|
|
39
|
+
Full AUDN decision history. Nothing disappears silently.
|
|
40
|
+
```js
|
|
41
|
+
memory.auditLog({ action: 'DELETE', since: '7d' });
|
|
42
|
+
// → [{ action, memory_id, content, reason, similarity, ran_at }]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### memory.briefing({ since }) — scoped date filtering
|
|
46
|
+
```js
|
|
47
|
+
await memory.briefing({ since: '7d' });
|
|
48
|
+
await memory.briefing({ since: '12h', minImportance: 0.7 });
|
|
49
|
+
await memory.briefing({ since: '2026-01-01', raw: true });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### memory.export() / memory.import()
|
|
53
|
+
Full graph serialisation with checksum integrity.
|
|
54
|
+
```js
|
|
55
|
+
const bundle = memory.export();
|
|
56
|
+
fs.writeFileSync('backup.vektor.json', JSON.stringify(bundle));
|
|
57
|
+
|
|
58
|
+
memory.import(bundle);
|
|
59
|
+
// → { imported: 244, skipped: 3, edgesAdded: 7100 }
|
|
60
|
+
|
|
61
|
+
memory.import(bundle, { dryRun: true }); // preview
|
|
62
|
+
memory.import(bundle, { mode: 'replace' }); // wipe and restore
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Namespace support
|
|
66
|
+
Scope all reads/writes to prevent project bleed.
|
|
67
|
+
```js
|
|
68
|
+
const memory = await createMemory({ agentId: 'my-agent', namespace: 'project-atlas' });
|
|
69
|
+
memory.listNamespaces();
|
|
70
|
+
// → [{ namespace: 'project-atlas', memories: 18 }, ...]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### TypeScript types
|
|
74
|
+
Full `.d.ts` declarations for all public API methods. No more flying blind in your IDE.
|
|
75
|
+
Add to `tsconfig.json`: `"types": ["vektor-slipstream"]`
|
|
76
|
+
|
|
77
|
+
### Structured error codes
|
|
78
|
+
Replace string catch blocks with reliable `VektorError.code` switching.
|
|
79
|
+
```js
|
|
80
|
+
import { VektorError, ERR } from 'vektor-slipstream/errors';
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await memory.remember(...)
|
|
84
|
+
} catch (e) {
|
|
85
|
+
if (e instanceof VektorError) {
|
|
86
|
+
switch (e.code) {
|
|
87
|
+
case ERR.LICENCE_INVALID: // handle
|
|
88
|
+
case ERR.EMBED_FAILED: // retry
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Schema changes
|
|
95
|
+
Run `npx vektor migrate` after updating, or migration runs automatically on startup.
|
|
96
|
+
|
|
97
|
+
New columns:
|
|
98
|
+
- `memories.pinned` INTEGER DEFAULT 0
|
|
99
|
+
- `memories.namespace` TEXT DEFAULT 'default'
|
|
100
|
+
- `memories.updated_at` INTEGER
|
|
101
|
+
|
|
102
|
+
New tables:
|
|
103
|
+
- `audn_log` — AUDN decision audit trail
|
|
104
|
+
- `rem_log` — REM cycle run history (if not already present)
|
|
105
|
+
- `vektor_meta` — schema version tracking
|
|
106
|
+
|
|
107
|
+
## Bug fixes
|
|
108
|
+
- REM cycle now skips pinned memories (previously could compress critical facts)
|
|
109
|
+
- AUDN deletions now logged before execution (previously silent)
|
|
110
|
+
- briefing() no longer returns stale summary when no memories exist in window
|
|
111
|
+
|
|
112
|
+
## Breaking changes
|
|
113
|
+
None. All new methods are additive. Existing code works unchanged.
|
|
114
|
+
Migration is backward-compatible — new columns have safe defaults.
|
|
115
|
+
|
|
116
|
+
## Gemini security review fixes (round 1 — applied)
|
|
117
|
+
- `briefing.js` — pinned memory query now has LIMIT 50 (context bomb prevention)
|
|
118
|
+
- `briefing.js` — `parseSince()` guards against `Date.now()` ms being passed as unix seconds
|
|
119
|
+
- `forget.js` — `forgetWhere()` selective error catching — infra errors re-thrown, only expected skips swallowed
|
|
120
|
+
- `namespace.js` — O(N) JS delete loop replaced with bulk SQL subquery (2 statements vs N*2)
|
|
121
|
+
- `inspect.js` — all `SUM()` aggregations wrapped in `IFNULL(..., 0)` — no more `null` in charts
|
|
122
|
+
- `migrate-137.js` — `PRAGMA table_info()` replaces brittle error-message string matching
|
|
123
|
+
|
|
124
|
+
## Gemini security review fixes (round 2 — applied)
|
|
125
|
+
- `export-import.js` — Fix 1: `IN (...memIds)` placeholders replaced with SQL subqueries — no more 32,766 param limit crash on large exports
|
|
126
|
+
- `export-import.js` — Fix 2: O(N) loop in `replace` mode replaced with bulk subquery deletes
|
|
127
|
+
- `export-import.js` — Fix 3: checksum now hashes full memories payload — content/importance tampering now detectable
|
|
128
|
+
- `export-import.js` — Fix 4: dangling edge guard — edges only inserted if both source and target exist in destination (`WHERE EXISTS`)
|
|
129
|
+
- `export-import.js` — `edgesSkipped` added to import return value with console.warn for partial imports
|
|
130
|
+
|
|
131
|
+
## Gemini security review fixes (round 3 — applied)
|
|
132
|
+
- `forget.js` — pinned edge orphan guard: blocks deleting a memory that shares
|
|
133
|
+
a graph edge with a pinned memory — prevents silent MAGMA traversal corruption
|
|
134
|
+
- `namespace.js` — SQLITE_BUSY retry loop: 3 attempts × 100ms using
|
|
135
|
+
`Atomics.wait` (correct sync sleep for better-sqlite3) before propagating error
|
|
136
|
+
- `export-import.js` — confirmed: empty bundle guard (line 103) already sits
|
|
137
|
+
before checksum computation (line 107) — correct order, no change needed
|
|
138
|
+
|
|
139
|
+
## Total fixes across 3 Gemini review rounds: 13
|
package/audn-log.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VEKTOR AUDN audit log — v1.3.7
|
|
3
|
+
* Records every ADD/UPDATE/DELETE/NO_OP decision AUDN makes
|
|
4
|
+
* before acting on it. Full transparency — nothing disappears silently.
|
|
5
|
+
*
|
|
6
|
+
* Schema additions required:
|
|
7
|
+
* CREATE TABLE IF NOT EXISTS audn_log (
|
|
8
|
+
* id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
9
|
+
* agent_id TEXT NOT NULL,
|
|
10
|
+
* namespace TEXT NOT NULL,
|
|
11
|
+
* action TEXT NOT NULL, -- ADD | UPDATE | DELETE | NO_OP
|
|
12
|
+
* memory_id TEXT, -- affected memory id (null for ADD before insert)
|
|
13
|
+
* content TEXT, -- snapshot of content at time of action
|
|
14
|
+
* reason TEXT, -- why AUDN made this decision
|
|
15
|
+
* similarity REAL, -- similarity score that triggered the decision
|
|
16
|
+
* ran_at INTEGER DEFAULT (unixepoch())
|
|
17
|
+
* );
|
|
18
|
+
* CREATE INDEX IF NOT EXISTS idx_audn_log_agent ON audn_log(agent_id, namespace, ran_at);
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* logAudn — call this inside AUDN before executing each decision
|
|
23
|
+
*
|
|
24
|
+
* @param {object} db
|
|
25
|
+
* @param {string} agentId
|
|
26
|
+
* @param {string} namespace
|
|
27
|
+
* @param {object} entry
|
|
28
|
+
* @param {string} entry.action - ADD | UPDATE | DELETE | NO_OP
|
|
29
|
+
* @param {string} entry.memoryId - memory id (if known)
|
|
30
|
+
* @param {string} entry.content - content snapshot
|
|
31
|
+
* @param {string} entry.reason - human-readable reason
|
|
32
|
+
* @param {number} entry.similarity - cosine score that triggered this
|
|
33
|
+
*/
|
|
34
|
+
export function logAudn(db, agentId, namespace, entry) {
|
|
35
|
+
db.prepare(`
|
|
36
|
+
INSERT INTO audn_log (agent_id, namespace, action, memory_id, content, reason, similarity)
|
|
37
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
38
|
+
`).run(
|
|
39
|
+
agentId,
|
|
40
|
+
namespace,
|
|
41
|
+
entry.action,
|
|
42
|
+
entry.memoryId || null,
|
|
43
|
+
entry.content ? entry.content.slice(0, 500) : null,
|
|
44
|
+
entry.reason || null,
|
|
45
|
+
entry.similarity || null
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* auditLog(opts) — retrieve AUDN decision history
|
|
51
|
+
*
|
|
52
|
+
* @param {object} db
|
|
53
|
+
* @param {string} agentId
|
|
54
|
+
* @param {string} namespace
|
|
55
|
+
* @param {object} opts
|
|
56
|
+
* @param {number} opts.limit - max rows (default 50)
|
|
57
|
+
* @param {string} opts.action - filter to specific action (ADD|UPDATE|DELETE|NO_OP)
|
|
58
|
+
* @param {string} opts.since - time filter — '7d', '24h', ISO date
|
|
59
|
+
* @returns {object[]}
|
|
60
|
+
*/
|
|
61
|
+
export function auditLog(db, agentId, namespace, opts = {}) {
|
|
62
|
+
const { limit = 50, action = null, since = null } = opts;
|
|
63
|
+
|
|
64
|
+
let sinceTs = null;
|
|
65
|
+
if (since) {
|
|
66
|
+
const rel = String(since).match(/^(\d+)(d|h|m)$/);
|
|
67
|
+
if (rel) {
|
|
68
|
+
const n = parseInt(rel[1]);
|
|
69
|
+
const unit = rel[2];
|
|
70
|
+
const seconds = unit === 'd' ? n * 86400 : unit === 'h' ? n * 3600 : n * 60;
|
|
71
|
+
sinceTs = Math.floor(Date.now() / 1000) - seconds;
|
|
72
|
+
} else {
|
|
73
|
+
sinceTs = Math.floor(Date.parse(since) / 1000);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const actionClause = action ? `AND action = '${action.toUpperCase()}'` : '';
|
|
78
|
+
const sinceClause = sinceTs ? `AND ran_at >= ${sinceTs}` : '';
|
|
79
|
+
|
|
80
|
+
return db.prepare(`
|
|
81
|
+
SELECT id, action, memory_id, content, reason, similarity, ran_at
|
|
82
|
+
FROM audn_log
|
|
83
|
+
WHERE agent_id = ? AND namespace = ?
|
|
84
|
+
${actionClause}
|
|
85
|
+
${sinceClause}
|
|
86
|
+
ORDER BY ran_at DESC
|
|
87
|
+
LIMIT ?
|
|
88
|
+
`).all(agentId, namespace, limit);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* auditStats() — summary counts by action type
|
|
93
|
+
*/
|
|
94
|
+
export function auditStats(db, agentId, namespace) {
|
|
95
|
+
return db.prepare(`
|
|
96
|
+
SELECT
|
|
97
|
+
action,
|
|
98
|
+
COUNT(*) as count,
|
|
99
|
+
MAX(ran_at) as last_at
|
|
100
|
+
FROM audn_log
|
|
101
|
+
WHERE agent_id = ? AND namespace = ?
|
|
102
|
+
GROUP BY action
|
|
103
|
+
ORDER BY count DESC
|
|
104
|
+
`).all(agentId, namespace);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* pruneAuditLog(days) — keep log from growing forever
|
|
109
|
+
* Call from REM cycle or a scheduled job
|
|
110
|
+
*/
|
|
111
|
+
export function pruneAuditLog(db, agentId, namespace, keepDays = 30) {
|
|
112
|
+
const cutoff = Math.floor(Date.now() / 1000) - keepDays * 86400;
|
|
113
|
+
const result = db.prepare(
|
|
114
|
+
`DELETE FROM audn_log WHERE agent_id = ? AND namespace = ? AND ran_at < ?`
|
|
115
|
+
).run(agentId, namespace, cutoff);
|
|
116
|
+
return { pruned: result.changes };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Integration into Memory class / AUDN loop:
|
|
121
|
+
*
|
|
122
|
+
* // Inside AUDN decision logic:
|
|
123
|
+
* logAudn(this.db, this.agentId, this.namespace, {
|
|
124
|
+
* action: 'DELETE',
|
|
125
|
+
* memoryId: existing.id,
|
|
126
|
+
* content: existing.content,
|
|
127
|
+
* reason: 'Contradicts newer memory with score 0.94',
|
|
128
|
+
* similarity: 0.94
|
|
129
|
+
* });
|
|
130
|
+
* // then execute the delete
|
|
131
|
+
*
|
|
132
|
+
* // Expose on Memory class:
|
|
133
|
+
* auditLog(opts = {}) {
|
|
134
|
+
* return auditLog(this.db, this.agentId, this.namespace, opts);
|
|
135
|
+
* }
|
|
136
|
+
*
|
|
137
|
+
* Usage:
|
|
138
|
+
* memory.auditLog({ action: 'DELETE', since: '7d' });
|
|
139
|
+
* // → [{ id, action:'DELETE', content:'...', reason:'...', ran_at }]
|
|
140
|
+
*
|
|
141
|
+
* memory.auditLog({ limit: 100 });
|
|
142
|
+
* // → last 100 AUDN decisions
|
|
143
|
+
*/
|
package/briefing.js
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VEKTOR briefing() date scoping — v1.3.7
|
|
3
|
+
* Adds `since` param to briefing() — filter to last N days/hours
|
|
4
|
+
* or an explicit ISO timestamp.
|
|
5
|
+
*
|
|
6
|
+
* Drop-in replacement for existing briefing() implementation.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { VektorError, ERR } from './errors.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Parse a `since` value into a Unix timestamp (seconds).
|
|
13
|
+
* Accepts:
|
|
14
|
+
* '1d' → last 1 day
|
|
15
|
+
* '7d' → last 7 days
|
|
16
|
+
* '12h' → last 12 hours
|
|
17
|
+
* '30m' → last 30 minutes
|
|
18
|
+
* '2026-01-01T00:00:00Z' → explicit ISO date
|
|
19
|
+
* 1735689600 → raw unix timestamp
|
|
20
|
+
*/
|
|
21
|
+
export function parseSince(since) {
|
|
22
|
+
if (!since) return null;
|
|
23
|
+
|
|
24
|
+
// Raw unix timestamp — guard against Date.now() (ms) being passed accidentally
|
|
25
|
+
// If number > 9999999999 it's milliseconds (year ~2001 in seconds) — convert it
|
|
26
|
+
if (typeof since === 'number') {
|
|
27
|
+
return since > 9_999_999_999 ? Math.floor(since / 1000) : since;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Relative shorthand: 7d, 12h, 30m
|
|
31
|
+
const rel = String(since).match(/^(\d+)(d|h|m)$/);
|
|
32
|
+
if (rel) {
|
|
33
|
+
const n = parseInt(rel[1]);
|
|
34
|
+
const unit = rel[2];
|
|
35
|
+
const seconds = unit === 'd' ? n * 86400 : unit === 'h' ? n * 3600 : n * 60;
|
|
36
|
+
return Math.floor(Date.now() / 1000) - seconds;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ISO date string
|
|
40
|
+
const ts = Date.parse(since);
|
|
41
|
+
if (!isNaN(ts)) return Math.floor(ts / 1000);
|
|
42
|
+
|
|
43
|
+
throw new VektorError(
|
|
44
|
+
ERR.MEMORY_READ_FAILED,
|
|
45
|
+
`Invalid since value: "${since}". Use "7d", "12h", "30m", ISO date, or unix timestamp.`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* briefing({ since, limit, minImportance })
|
|
51
|
+
* Returns a structured summary of recent memories for agent context injection.
|
|
52
|
+
*
|
|
53
|
+
* @param {object} db
|
|
54
|
+
* @param {string} agentId
|
|
55
|
+
* @param {string} namespace
|
|
56
|
+
* @param {Function} summariseFn - LLM summarise function (existing REM summariser)
|
|
57
|
+
* @param {object} opts
|
|
58
|
+
* @param {string|number} opts.since - time filter (default: '1d')
|
|
59
|
+
* @param {number} opts.limit - max memories (default: 20)
|
|
60
|
+
* @param {number} opts.minImportance - filter by importance score (default: 0)
|
|
61
|
+
* @param {boolean} opts.raw - return raw memories, skip LLM summary
|
|
62
|
+
* @returns {object} { period, memoryCount, pinned, summary, memories }
|
|
63
|
+
*/
|
|
64
|
+
export async function briefing(db, agentId, namespace, summariseFn, opts = {}) {
|
|
65
|
+
const {
|
|
66
|
+
since = '1d',
|
|
67
|
+
limit = 20,
|
|
68
|
+
minImportance = 0,
|
|
69
|
+
raw = false
|
|
70
|
+
} = opts;
|
|
71
|
+
|
|
72
|
+
const sinceTs = parseSince(since);
|
|
73
|
+
const sinceClause = sinceTs ? `AND created_at >= ${sinceTs}` : '';
|
|
74
|
+
const importanceClause = minImportance > 0 ? `AND importance >= ${minImportance}` : '';
|
|
75
|
+
|
|
76
|
+
// Fetch scoped memories
|
|
77
|
+
const memories = db.prepare(`
|
|
78
|
+
SELECT id, content, summary, importance, pinned, created_at
|
|
79
|
+
FROM memories
|
|
80
|
+
WHERE agent_id = ? AND namespace = ?
|
|
81
|
+
${sinceClause}
|
|
82
|
+
${importanceClause}
|
|
83
|
+
ORDER BY importance DESC, created_at DESC
|
|
84
|
+
LIMIT ?
|
|
85
|
+
`).all(agentId, namespace, limit);
|
|
86
|
+
|
|
87
|
+
// Always fetch pinned regardless of time window — hard cap 50 to prevent context bomb
|
|
88
|
+
// (an agent running for months could accumulate hundreds of pinned memories)
|
|
89
|
+
const pinnedLimit = 50;
|
|
90
|
+
const pinned = db.prepare(`
|
|
91
|
+
SELECT id, content, summary, importance, created_at
|
|
92
|
+
FROM memories
|
|
93
|
+
WHERE agent_id = ? AND namespace = ? AND pinned = 1
|
|
94
|
+
ORDER BY importance DESC
|
|
95
|
+
LIMIT ${pinnedLimit}
|
|
96
|
+
`).all(agentId, namespace);
|
|
97
|
+
|
|
98
|
+
if (raw) {
|
|
99
|
+
return {
|
|
100
|
+
period: since,
|
|
101
|
+
memoryCount: memories.length,
|
|
102
|
+
pinned,
|
|
103
|
+
memories
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Build prompt context for LLM summary
|
|
108
|
+
const context = [
|
|
109
|
+
pinned.length > 0
|
|
110
|
+
? `PINNED (permanent):\n${pinned.map(m => `- ${m.summary || m.content}`).join('\n')}`
|
|
111
|
+
: null,
|
|
112
|
+
memories.length > 0
|
|
113
|
+
? `RECENT (${since}):\n${memories.map(m => `- [${m.importance?.toFixed(2)}] ${m.summary || m.content}`).join('\n')}`
|
|
114
|
+
: 'No recent memories in this period.'
|
|
115
|
+
].filter(Boolean).join('\n\n');
|
|
116
|
+
|
|
117
|
+
const summary = await summariseFn(
|
|
118
|
+
`Produce a concise agent briefing from these memories. Lead with pinned facts, then recent activity.\n\n${context}`
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
period: since,
|
|
123
|
+
memoryCount: memories.length,
|
|
124
|
+
pinnedCount: pinned.length,
|
|
125
|
+
pinned,
|
|
126
|
+
memories,
|
|
127
|
+
summary
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Integration into Memory class:
|
|
133
|
+
*
|
|
134
|
+
* async briefing(opts = {}) {
|
|
135
|
+
* return briefing(this.db, this.agentId, this.namespace, this._summarise.bind(this), opts);
|
|
136
|
+
* }
|
|
137
|
+
*
|
|
138
|
+
* Usage:
|
|
139
|
+
* await memory.briefing();
|
|
140
|
+
* // → last 24h summary (default)
|
|
141
|
+
*
|
|
142
|
+
* await memory.briefing({ since: '7d' });
|
|
143
|
+
* // → last 7 days
|
|
144
|
+
*
|
|
145
|
+
* await memory.briefing({ since: '2026-01-01', minImportance: 0.7 });
|
|
146
|
+
* // → since Jan 1st, high importance only
|
|
147
|
+
*
|
|
148
|
+
* await memory.briefing({ raw: true, since: '1h' });
|
|
149
|
+
* // → raw memory objects, no LLM call
|
|
150
|
+
*/
|