openclawdreams 3.0.4 → 3.0.6
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 +26 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/dist/bin/electricsheep.d.ts +0 -3
- package/dist/bin/electricsheep.d.ts.map +0 -1
- package/dist/bin/electricsheep.js +0 -4
- package/dist/bin/electricsheep.js.map +0 -1
- package/dist/bin/openclawdreams.d.ts +0 -3
- package/dist/bin/openclawdreams.d.ts.map +0 -1
- package/dist/bin/openclawdreams.js +0 -4
- package/dist/bin/openclawdreams.js.map +0 -1
- package/dist/src/backfill.d.ts +0 -2
- package/dist/src/backfill.d.ts.map +0 -1
- package/dist/src/backfill.js +0 -63
- package/dist/src/backfill.js.map +0 -1
- package/dist/src/budget.d.ts +0 -28
- package/dist/src/budget.d.ts.map +0 -1
- package/dist/src/budget.js +0 -117
- package/dist/src/budget.js.map +0 -1
- package/dist/src/cli.d.ts +0 -19
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js +0 -584
- package/dist/src/cli.js.map +0 -1
- package/dist/src/config.d.ts +0 -76
- package/dist/src/config.d.ts.map +0 -1
- package/dist/src/config.js +0 -178
- package/dist/src/config.js.map +0 -1
- package/dist/src/crypto.d.ts +0 -19
- package/dist/src/crypto.d.ts.map +0 -1
- package/dist/src/crypto.js +0 -70
- package/dist/src/crypto.js.map +0 -1
- package/dist/src/dreamer.d.ts +0 -68
- package/dist/src/dreamer.d.ts.map +0 -1
- package/dist/src/dreamer.js +0 -550
- package/dist/src/dreamer.js.map +0 -1
- package/dist/src/entropy.d.ts +0 -23
- package/dist/src/entropy.d.ts.map +0 -1
- package/dist/src/entropy.js +0 -188
- package/dist/src/entropy.js.map +0 -1
- package/dist/src/filter.d.ts +0 -30
- package/dist/src/filter.d.ts.map +0 -1
- package/dist/src/filter.js +0 -124
- package/dist/src/filter.js.map +0 -1
- package/dist/src/identity.d.ts +0 -29
- package/dist/src/identity.d.ts.map +0 -1
- package/dist/src/identity.js +0 -83
- package/dist/src/identity.js.map +0 -1
- package/dist/src/index.d.ts +0 -14
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -463
- package/dist/src/index.js.map +0 -1
- package/dist/src/ingestion.d.ts +0 -22
- package/dist/src/ingestion.d.ts.map +0 -1
- package/dist/src/ingestion.js +0 -101
- package/dist/src/ingestion.js.map +0 -1
- package/dist/src/llm.d.ts +0 -26
- package/dist/src/llm.d.ts.map +0 -1
- package/dist/src/llm.js +0 -40
- package/dist/src/llm.js.map +0 -1
- package/dist/src/logger.d.ts +0 -6
- package/dist/src/logger.d.ts.map +0 -1
- package/dist/src/logger.js +0 -32
- package/dist/src/logger.js.map +0 -1
- package/dist/src/memory.d.ts +0 -96
- package/dist/src/memory.d.ts.map +0 -1
- package/dist/src/memory.js +0 -467
- package/dist/src/memory.js.map +0 -1
- package/dist/src/meta-loop.d.ts +0 -23
- package/dist/src/meta-loop.d.ts.map +0 -1
- package/dist/src/meta-loop.js +0 -72
- package/dist/src/meta-loop.js.map +0 -1
- package/dist/src/moltbook-search.d.ts +0 -23
- package/dist/src/moltbook-search.d.ts.map +0 -1
- package/dist/src/moltbook-search.js +0 -85
- package/dist/src/moltbook-search.js.map +0 -1
- package/dist/src/moltbook.d.ts +0 -34
- package/dist/src/moltbook.d.ts.map +0 -1
- package/dist/src/moltbook.js +0 -192
- package/dist/src/moltbook.js.map +0 -1
- package/dist/src/nightmare.d.ts +0 -11
- package/dist/src/nightmare.d.ts.map +0 -1
- package/dist/src/nightmare.js +0 -126
- package/dist/src/nightmare.js.map +0 -1
- package/dist/src/notify.d.ts +0 -20
- package/dist/src/notify.d.ts.map +0 -1
- package/dist/src/notify.js +0 -95
- package/dist/src/notify.js.map +0 -1
- package/dist/src/persona.d.ts +0 -30
- package/dist/src/persona.d.ts.map +0 -1
- package/dist/src/persona.js +0 -292
- package/dist/src/persona.js.map +0 -1
- package/dist/src/reflection.d.ts +0 -26
- package/dist/src/reflection.d.ts.map +0 -1
- package/dist/src/reflection.js +0 -127
- package/dist/src/reflection.js.map +0 -1
- package/dist/src/rhythm.d.ts +0 -19
- package/dist/src/rhythm.d.ts.map +0 -1
- package/dist/src/rhythm.js +0 -130
- package/dist/src/rhythm.js.map +0 -1
- package/dist/src/state.d.ts +0 -7
- package/dist/src/state.d.ts.map +0 -1
- package/dist/src/state.js +0 -40
- package/dist/src/state.js.map +0 -1
- package/dist/src/synthesis.d.ts +0 -29
- package/dist/src/synthesis.d.ts.map +0 -1
- package/dist/src/synthesis.js +0 -144
- package/dist/src/synthesis.js.map +0 -1
- package/dist/src/topics.d.ts +0 -19
- package/dist/src/topics.d.ts.map +0 -1
- package/dist/src/topics.js +0 -84
- package/dist/src/topics.js.map +0 -1
- package/dist/src/types.d.ts +0 -253
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/types.js +0 -5
- package/dist/src/types.js.map +0 -1
- package/dist/src/vocabulary.d.ts +0 -18
- package/dist/src/vocabulary.d.ts.map +0 -1
- package/dist/src/vocabulary.js +0 -121
- package/dist/src/vocabulary.js.map +0 -1
- package/dist/src/waking.d.ts +0 -27
- package/dist/src/waking.d.ts.map +0 -1
- package/dist/src/waking.js +0 -188
- package/dist/src/waking.js.map +0 -1
- package/dist/src/web-search.d.ts +0 -23
- package/dist/src/web-search.d.ts.map +0 -1
- package/dist/src/web-search.js +0 -64
- package/dist/src/web-search.js.map +0 -1
package/dist/src/llm.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared LLM client utilities.
|
|
3
|
-
*
|
|
4
|
-
* Provides retry configuration and call helpers used by both
|
|
5
|
-
* the waking and dreamer modules. The actual LLM client is
|
|
6
|
-
* provided by the OpenClaw gateway (see index.ts).
|
|
7
|
-
*/
|
|
8
|
-
import pRetry from "p-retry";
|
|
9
|
-
import { AGENT_MODEL } from "./config.js";
|
|
10
|
-
import logger from "./logger.js";
|
|
11
|
-
/** Standard retry options for waking-state LLM calls. */
|
|
12
|
-
export const WAKING_RETRY_OPTS = {
|
|
13
|
-
retries: 3,
|
|
14
|
-
minTimeout: 1000,
|
|
15
|
-
maxTimeout: 10000,
|
|
16
|
-
onFailedAttempt: (error) => {
|
|
17
|
-
logger.warn(`LLM attempt failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
/** Retry options for dream-cycle LLM calls (longer timeouts). */
|
|
21
|
-
export const DREAM_RETRY_OPTS = {
|
|
22
|
-
retries: 3,
|
|
23
|
-
minTimeout: 2000,
|
|
24
|
-
maxTimeout: 20000,
|
|
25
|
-
onFailedAttempt: (error) => {
|
|
26
|
-
logger.warn(`Dream generation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
27
|
-
},
|
|
28
|
-
};
|
|
29
|
-
/**
|
|
30
|
-
* Helper: call LLM with retry and return the response.
|
|
31
|
-
*/
|
|
32
|
-
export function callWithRetry(client, params, retryOpts = WAKING_RETRY_OPTS) {
|
|
33
|
-
return pRetry(() => client.createMessage({
|
|
34
|
-
model: params.model ?? AGENT_MODEL,
|
|
35
|
-
maxTokens: params.maxTokens,
|
|
36
|
-
system: params.system,
|
|
37
|
-
messages: params.messages,
|
|
38
|
-
}), retryOpts);
|
|
39
|
-
}
|
|
40
|
-
//# sourceMappingURL=llm.js.map
|
package/dist/src/llm.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"llm.js","sourceRoot":"","sources":["../../src/llm.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,MAAwC,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,MAAM,MAAM,aAAa,CAAC;AAGjC,yDAAyD;AACzD,MAAM,CAAC,MAAM,iBAAiB,GAAiB;IAC7C,OAAO,EAAE,CAAC;IACV,UAAU,EAAE,IAAI;IAChB,UAAU,EAAE,KAAK;IACjB,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE;QACzB,MAAM,CAAC,IAAI,CACT,uBAAuB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAChF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF,iEAAiE;AACjE,MAAM,CAAC,MAAM,gBAAgB,GAAiB;IAC5C,OAAO,EAAE,CAAC;IACV,UAAU,EAAE,IAAI;IAChB,UAAU,EAAE,KAAK;IACjB,eAAe,EAAE,CAAC,KAAK,EAAE,EAAE;QACzB,MAAM,CAAC,IAAI,CACT,4BAA4B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACrF,CAAC;IACJ,CAAC;CACF,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAiB,EACjB,MAKC,EACD,YAA0B,iBAAiB;IAE3C,OAAO,MAAM,CACX,GAAG,EAAE,CACH,MAAM,CAAC,aAAa,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,WAAW;QAClC,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC,EACJ,SAAS,CACV,CAAC;AACJ,CAAC"}
|
package/dist/src/logger.d.ts
DELETED
package/dist/src/logger.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AACA,OAAO,2BAA2B,CAAC;AAGnC,QAAA,MAAM,MAAM,0BA4BV,CAAC;AAEH,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAEjD;AAED,wBAAgB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAK3C;AAED,eAAe,MAAM,CAAC"}
|
package/dist/src/logger.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { createLogger, format, transports } from "winston";
|
|
2
|
-
import "winston-daily-rotate-file";
|
|
3
|
-
import { getDataDir } from "./config.js";
|
|
4
|
-
const logger = createLogger({
|
|
5
|
-
level: "info",
|
|
6
|
-
format: format.combine(format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), format.printf(({ timestamp, level, message }) => `${timestamp} [${level.toUpperCase()}]: ${message}`)),
|
|
7
|
-
transports: [
|
|
8
|
-
new transports.DailyRotateFile({
|
|
9
|
-
dirname: getDataDir(),
|
|
10
|
-
filename: "openclawdreams-%DATE%.log",
|
|
11
|
-
datePattern: "YYYY-MM-DD",
|
|
12
|
-
zippedArchive: true,
|
|
13
|
-
maxSize: "20m",
|
|
14
|
-
maxFiles: "14d",
|
|
15
|
-
level: "debug",
|
|
16
|
-
}),
|
|
17
|
-
new transports.Console({
|
|
18
|
-
format: format.combine(format.colorize(), format.printf(({ timestamp, level, message }) => `${timestamp} [${level}]: ${message}`)),
|
|
19
|
-
}),
|
|
20
|
-
],
|
|
21
|
-
});
|
|
22
|
-
export function setVerbose(verbose) {
|
|
23
|
-
logger.level = verbose ? "debug" : "info";
|
|
24
|
-
}
|
|
25
|
-
export function closeLogger() {
|
|
26
|
-
return new Promise((resolve) => {
|
|
27
|
-
logger.on("finish", resolve);
|
|
28
|
-
logger.end();
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
export default logger;
|
|
32
|
-
//# sourceMappingURL=logger.js.map
|
package/dist/src/logger.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC3D,OAAO,2BAA2B,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,MAAM,MAAM,GAAG,YAAY,CAAC;IAC1B,KAAK,EAAE,MAAM;IACb,MAAM,EAAE,MAAM,CAAC,OAAO,CACpB,MAAM,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,qBAAqB,EAAE,CAAC,EACnD,MAAM,CAAC,MAAM,CACX,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAChC,GAAG,SAAS,KAAK,KAAK,CAAC,WAAW,EAAE,MAAM,OAAO,EAAE,CACtD,CACF;IACD,UAAU,EAAE;QACV,IAAI,UAAU,CAAC,eAAe,CAAC;YAC7B,OAAO,EAAE,UAAU,EAAE;YACrB,QAAQ,EAAE,2BAA2B;YACrC,WAAW,EAAE,YAAY;YACzB,aAAa,EAAE,IAAI;YACnB,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,KAAK;YACf,KAAK,EAAE,OAAO;SACf,CAAC;QACF,IAAI,UAAU,CAAC,OAAO,CAAC;YACrB,MAAM,EAAE,MAAM,CAAC,OAAO,CACpB,MAAM,CAAC,QAAQ,EAAE,EACjB,MAAM,CAAC,MAAM,CACX,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,GAAG,SAAS,KAAK,KAAK,MAAM,OAAO,EAAE,CACzE,CACF;SACF,CAAC;KACH;CACF,CAAC,CAAC;AAEH,MAAM,UAAU,UAAU,CAAC,OAAgB;IACzC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,EAAE,CAAC;IACf,CAAC,CAAC,CAAC;AACL,CAAC;AAED,eAAe,MAAM,CAAC"}
|
package/dist/src/memory.d.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Encrypted deep memory system.
|
|
3
|
-
*
|
|
4
|
-
* All memories are encrypted with AES-256-GCM in a SQLite database.
|
|
5
|
-
* The waking agent writes to deep memory but cannot read it — only
|
|
6
|
-
* the dream process can decrypt. Context for LLM prompts is formatted
|
|
7
|
-
* via `formatDeepMemoryContext()`.
|
|
8
|
-
*/
|
|
9
|
-
import type { DecryptedMemory, DeepMemoryStats, MemoryEntry } from "./types.js";
|
|
10
|
-
/**
|
|
11
|
-
* Parse `git diff --stat` output into structured FileDiff[].
|
|
12
|
-
*/
|
|
13
|
-
export declare function parseDiffStat(diffStat: string): import("./types.js").FileDiff[];
|
|
14
|
-
/**
|
|
15
|
-
* Close the shared SQLite connection. Safe to call multiple times.
|
|
16
|
-
* After closing, the next getDb() call will reopen.
|
|
17
|
-
*/
|
|
18
|
-
export declare function closeDb(): void;
|
|
19
|
-
export declare function storeDeepMemory(content: Record<string, unknown>, category?: string): number | bigint;
|
|
20
|
-
export declare function getDeepMemoryById(id: number | bigint): DecryptedMemory | null;
|
|
21
|
-
export declare function retrieveUndreamedMemories(): DecryptedMemory[];
|
|
22
|
-
export declare function markAsDreamed(memoryIds: number[]): void;
|
|
23
|
-
export declare function deepMemoryStats(): DeepMemoryStats;
|
|
24
|
-
export interface DeepMemoryQueryOptions {
|
|
25
|
-
limit?: number;
|
|
26
|
-
categories?: string[];
|
|
27
|
-
undreamedOnly?: boolean;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Query deep memory with optional filters. Decrypts results, handles
|
|
31
|
-
* corruption gracefully, returns in chronological order.
|
|
32
|
-
*/
|
|
33
|
-
export declare function getRecentDeepMemories(options?: DeepMemoryQueryOptions): DecryptedMemory[];
|
|
34
|
-
/**
|
|
35
|
-
* Format decrypted memories as a text block for LLM prompts.
|
|
36
|
-
*
|
|
37
|
-
* Extracts `content.summary` when available, falls back to truncated JSON.
|
|
38
|
-
* Respects an approximate token budget (1 token ≈ 4 chars).
|
|
39
|
-
*/
|
|
40
|
-
export declare function formatDeepMemoryContext(memories?: DecryptedMemory[], maxTokensApprox?: number): string;
|
|
41
|
-
/** Register a new dream. INSERT OR IGNORE (idempotent). */
|
|
42
|
-
export declare function registerDream(filename: string, title: string, dreamDate: string, options?: {
|
|
43
|
-
isNightmare?: boolean;
|
|
44
|
-
isMetaSynthesis?: boolean;
|
|
45
|
-
sourceFilenames?: string[];
|
|
46
|
-
deepMemoryId?: number | bigint;
|
|
47
|
-
}): void;
|
|
48
|
-
/** Increment remember_count for a dream that was selected. */
|
|
49
|
-
export declare function incrementRememberCount(filename: string): void;
|
|
50
|
-
/**
|
|
51
|
-
* Weighted random selection: score = 1/(count+1) * max(1, age_days).
|
|
52
|
-
* Fetch all rows from SQLite, compute scores in JS, do weighted pick.
|
|
53
|
-
* Returns filename and deep_memory_id, or null if table is empty.
|
|
54
|
-
*/
|
|
55
|
-
export declare function selectDreamToRemember(today: string): {
|
|
56
|
-
filename: string;
|
|
57
|
-
deep_memory_id: number | null;
|
|
58
|
-
} | null;
|
|
59
|
-
/** For inspection/testing. */
|
|
60
|
-
export declare function getDreamRemembrances(): Array<{
|
|
61
|
-
filename: string;
|
|
62
|
-
title: string;
|
|
63
|
-
dream_date: string;
|
|
64
|
-
remember_count: number;
|
|
65
|
-
is_nightmare: number;
|
|
66
|
-
is_meta_synthesis: number;
|
|
67
|
-
source_filenames: string | null;
|
|
68
|
-
deep_memory_id: number | null;
|
|
69
|
-
}>;
|
|
70
|
-
export interface DreamLineageRow {
|
|
71
|
-
id: number;
|
|
72
|
-
dream_filename: string;
|
|
73
|
-
parent_memory_ids: string | null;
|
|
74
|
-
thematic_kin: string | null;
|
|
75
|
-
dominant_concepts: string | null;
|
|
76
|
-
created_at: string;
|
|
77
|
-
}
|
|
78
|
-
export declare function insertDreamLineage(dreamFilename: string, parentMemoryIds: number[], thematicKin: string[], dominantConcepts: string[]): void;
|
|
79
|
-
export declare function getAllDreamLineage(): DreamLineageRow[];
|
|
80
|
-
export declare function getDreamLineageByFilename(filename: string): DreamLineageRow | null;
|
|
81
|
-
/**
|
|
82
|
-
* Find thematic kin for a dream by computing concept overlap with all prior dreams.
|
|
83
|
-
* Returns filenames of dreams with overlap >= threshold (default 0.3).
|
|
84
|
-
*/
|
|
85
|
-
export declare function findThematicKin(currentConcepts: string[], currentFilename: string, threshold?: number): Array<{
|
|
86
|
-
filename: string;
|
|
87
|
-
overlap: number;
|
|
88
|
-
}>;
|
|
89
|
-
/**
|
|
90
|
-
* Store a structured MemoryEntry in encrypted deep memory.
|
|
91
|
-
*
|
|
92
|
-
* Accepts either a MemoryEntry directly, or a legacy (summary, fullContext)
|
|
93
|
-
* pair for backward compatibility.
|
|
94
|
-
*/
|
|
95
|
-
export declare function remember(summaryOrEntry: string | MemoryEntry, fullContextOrCategory?: Record<string, unknown> | string, category?: string): void;
|
|
96
|
-
//# sourceMappingURL=memory.d.ts.map
|
package/dist/src/memory.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../src/memory.ts"],"names":[],"mappings":"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"}
|
package/dist/src/memory.js
DELETED
|
@@ -1,467 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Encrypted deep memory system.
|
|
3
|
-
*
|
|
4
|
-
* All memories are encrypted with AES-256-GCM in a SQLite database.
|
|
5
|
-
* The waking agent writes to deep memory but cannot read it — only
|
|
6
|
-
* the dream process can decrypt. Context for LLM prompts is formatted
|
|
7
|
-
* via `formatDeepMemoryContext()`.
|
|
8
|
-
*/
|
|
9
|
-
import { createHash } from "node:crypto";
|
|
10
|
-
import Database from "better-sqlite3";
|
|
11
|
-
import { getCipher } from "./crypto.js";
|
|
12
|
-
import { getDeepMemoryDb, DEEP_MEMORY_CONTEXT_TOKENS } from "./config.js";
|
|
13
|
-
/**
|
|
14
|
-
* Normalize a decrypted payload into a MemoryEntry.
|
|
15
|
-
* Handles backward compatibility with legacy plain-object entries
|
|
16
|
-
* that have `summary` and `file_diffs` as flat fields.
|
|
17
|
-
*/
|
|
18
|
-
function normalizeMemoryEntry(raw, rowTimestamp) {
|
|
19
|
-
// Already a MemoryEntry (has text_summary)
|
|
20
|
-
if (typeof raw === "object" &&
|
|
21
|
-
raw !== null &&
|
|
22
|
-
typeof raw.text_summary === "string") {
|
|
23
|
-
return raw;
|
|
24
|
-
}
|
|
25
|
-
// Plain string (very old format)
|
|
26
|
-
if (typeof raw === "string") {
|
|
27
|
-
return { text_summary: raw, timestamp: Date.parse(rowTimestamp) || Date.now() };
|
|
28
|
-
}
|
|
29
|
-
// Legacy object with `summary` field
|
|
30
|
-
const obj = raw;
|
|
31
|
-
const textSummary = typeof obj.summary === "string" ? obj.summary : JSON.stringify(obj).slice(0, 500);
|
|
32
|
-
const entry = {
|
|
33
|
-
text_summary: textSummary,
|
|
34
|
-
timestamp: Date.parse(rowTimestamp) || Date.now(),
|
|
35
|
-
};
|
|
36
|
-
// Migrate legacy flat file_diffs string
|
|
37
|
-
if (typeof obj.file_diffs === "string" && obj.file_diffs) {
|
|
38
|
-
entry.file_diffs = parseDiffStat(obj.file_diffs);
|
|
39
|
-
}
|
|
40
|
-
return entry;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Parse `git diff --stat` output into structured FileDiff[].
|
|
44
|
-
*/
|
|
45
|
-
export function parseDiffStat(diffStat) {
|
|
46
|
-
const lines = diffStat.split("\n").filter((l) => l.includes("|"));
|
|
47
|
-
return lines.map((line) => {
|
|
48
|
-
const match = line.match(/^\s*(.+?)\s*\|\s*(\d+)/);
|
|
49
|
-
if (!match)
|
|
50
|
-
return { path: line.trim(), additions: 0, deletions: 0 };
|
|
51
|
-
const path = match[1].trim();
|
|
52
|
-
const total = parseInt(match[2], 10);
|
|
53
|
-
const plusCount = (line.match(/\+/g) || []).length;
|
|
54
|
-
const minusCount = (line.match(/-/g) || []).length;
|
|
55
|
-
// Approximate: distribute total changes by + and - symbols in the stat line
|
|
56
|
-
const ratio = plusCount + minusCount > 0 ? plusCount / (plusCount + minusCount) : 0.5;
|
|
57
|
-
return {
|
|
58
|
-
path,
|
|
59
|
-
additions: Math.round(total * ratio),
|
|
60
|
-
deletions: Math.round(total * (1 - ratio)),
|
|
61
|
-
};
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
// ─── Deep Memory (Encrypted) ────────────────────────────────────────────────
|
|
65
|
-
let _db = null;
|
|
66
|
-
function getDb() {
|
|
67
|
-
if (_db)
|
|
68
|
-
return _db;
|
|
69
|
-
const dbPath = getDeepMemoryDb();
|
|
70
|
-
const db = new Database(dbPath);
|
|
71
|
-
db.pragma("journal_mode = WAL");
|
|
72
|
-
db.exec(`
|
|
73
|
-
CREATE TABLE IF NOT EXISTS deep_memories (
|
|
74
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
75
|
-
timestamp TEXT NOT NULL,
|
|
76
|
-
category TEXT NOT NULL,
|
|
77
|
-
encrypted_blob TEXT NOT NULL,
|
|
78
|
-
content_hash TEXT NOT NULL,
|
|
79
|
-
dreamed INTEGER DEFAULT 0,
|
|
80
|
-
dream_date TEXT
|
|
81
|
-
)
|
|
82
|
-
`);
|
|
83
|
-
db.exec(`
|
|
84
|
-
CREATE TABLE IF NOT EXISTS dream_remembrances (
|
|
85
|
-
filename TEXT PRIMARY KEY,
|
|
86
|
-
title TEXT NOT NULL,
|
|
87
|
-
dream_date TEXT NOT NULL,
|
|
88
|
-
remember_count INTEGER NOT NULL DEFAULT 0,
|
|
89
|
-
registered_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
|
90
|
-
)
|
|
91
|
-
`);
|
|
92
|
-
// Migrate: add new columns if they don't exist yet
|
|
93
|
-
const existingCols = db.pragma("table_info(dream_remembrances)").map((c) => c.name);
|
|
94
|
-
if (!existingCols.includes("is_nightmare")) {
|
|
95
|
-
db.exec("ALTER TABLE dream_remembrances ADD COLUMN is_nightmare INTEGER NOT NULL DEFAULT 0");
|
|
96
|
-
}
|
|
97
|
-
if (!existingCols.includes("is_meta_synthesis")) {
|
|
98
|
-
db.exec("ALTER TABLE dream_remembrances ADD COLUMN is_meta_synthesis INTEGER NOT NULL DEFAULT 0");
|
|
99
|
-
}
|
|
100
|
-
if (!existingCols.includes("source_filenames")) {
|
|
101
|
-
db.exec("ALTER TABLE dream_remembrances ADD COLUMN source_filenames TEXT");
|
|
102
|
-
}
|
|
103
|
-
if (!existingCols.includes("deep_memory_id")) {
|
|
104
|
-
db.exec("ALTER TABLE dream_remembrances ADD COLUMN deep_memory_id INTEGER");
|
|
105
|
-
}
|
|
106
|
-
// Dream lineage table for tracking dream genealogy
|
|
107
|
-
db.exec(`
|
|
108
|
-
CREATE TABLE IF NOT EXISTS dream_lineage (
|
|
109
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
110
|
-
dream_filename TEXT NOT NULL,
|
|
111
|
-
parent_memory_ids TEXT,
|
|
112
|
-
thematic_kin TEXT,
|
|
113
|
-
dominant_concepts TEXT,
|
|
114
|
-
created_at TEXT NOT NULL
|
|
115
|
-
)
|
|
116
|
-
`);
|
|
117
|
-
db.exec(`
|
|
118
|
-
CREATE INDEX IF NOT EXISTS idx_deep_dreamed
|
|
119
|
-
ON deep_memories(dreamed, timestamp)
|
|
120
|
-
`);
|
|
121
|
-
db.exec(`
|
|
122
|
-
CREATE INDEX IF NOT EXISTS idx_deep_category
|
|
123
|
-
ON deep_memories(category)
|
|
124
|
-
`);
|
|
125
|
-
db.exec(`
|
|
126
|
-
CREATE INDEX IF NOT EXISTS idx_deep_timestamp
|
|
127
|
-
ON deep_memories(timestamp)
|
|
128
|
-
`);
|
|
129
|
-
_db = db;
|
|
130
|
-
return db;
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Close the shared SQLite connection. Safe to call multiple times.
|
|
134
|
-
* After closing, the next getDb() call will reopen.
|
|
135
|
-
*/
|
|
136
|
-
export function closeDb() {
|
|
137
|
-
if (_db) {
|
|
138
|
-
_db.close();
|
|
139
|
-
_db = null;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
export function storeDeepMemory(content, category = "interaction") {
|
|
143
|
-
const db = getDb();
|
|
144
|
-
const cipher = getCipher();
|
|
145
|
-
const raw = JSON.stringify(content);
|
|
146
|
-
const encrypted = cipher.encrypt(raw);
|
|
147
|
-
const contentHash = createHash("sha256").update(raw).digest("hex").slice(0, 16);
|
|
148
|
-
const result = db
|
|
149
|
-
.prepare(`INSERT INTO deep_memories (timestamp, category, encrypted_blob, content_hash)
|
|
150
|
-
VALUES (?, ?, ?, ?)`)
|
|
151
|
-
.run(new Date().toISOString(), category, encrypted, contentHash);
|
|
152
|
-
return result.lastInsertRowid;
|
|
153
|
-
}
|
|
154
|
-
export function getDeepMemoryById(id) {
|
|
155
|
-
const db = getDb();
|
|
156
|
-
const cipher = getCipher();
|
|
157
|
-
const row = db
|
|
158
|
-
.prepare(`SELECT id, timestamp, category, encrypted_blob
|
|
159
|
-
FROM deep_memories WHERE id = ?`)
|
|
160
|
-
.get(id);
|
|
161
|
-
if (!row)
|
|
162
|
-
return null;
|
|
163
|
-
try {
|
|
164
|
-
const decrypted = JSON.parse(cipher.decrypt(row.encrypted_blob));
|
|
165
|
-
return {
|
|
166
|
-
id: row.id,
|
|
167
|
-
timestamp: row.timestamp,
|
|
168
|
-
category: row.category,
|
|
169
|
-
content: normalizeMemoryEntry(decrypted, row.timestamp),
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
catch {
|
|
173
|
-
return {
|
|
174
|
-
id: row.id,
|
|
175
|
-
timestamp: row.timestamp,
|
|
176
|
-
category: "corrupted",
|
|
177
|
-
content: {
|
|
178
|
-
text_summary: "This memory could not be recovered.",
|
|
179
|
-
timestamp: Date.parse(row.timestamp) || Date.now(),
|
|
180
|
-
},
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
export function retrieveUndreamedMemories() {
|
|
185
|
-
const db = getDb();
|
|
186
|
-
const cipher = getCipher();
|
|
187
|
-
const rows = db
|
|
188
|
-
.prepare(`SELECT id, timestamp, category, encrypted_blob
|
|
189
|
-
FROM deep_memories WHERE dreamed = 0 AND category NOT IN ('dream', 'nightmare') ORDER BY timestamp`)
|
|
190
|
-
.all();
|
|
191
|
-
const memories = [];
|
|
192
|
-
for (const row of rows) {
|
|
193
|
-
try {
|
|
194
|
-
const decrypted = JSON.parse(cipher.decrypt(row.encrypted_blob));
|
|
195
|
-
memories.push({
|
|
196
|
-
id: row.id,
|
|
197
|
-
timestamp: row.timestamp,
|
|
198
|
-
category: row.category,
|
|
199
|
-
content: normalizeMemoryEntry(decrypted, row.timestamp),
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
catch {
|
|
203
|
-
memories.push({
|
|
204
|
-
id: row.id,
|
|
205
|
-
timestamp: row.timestamp,
|
|
206
|
-
category: "corrupted",
|
|
207
|
-
content: {
|
|
208
|
-
text_summary: "This memory could not be recovered.",
|
|
209
|
-
timestamp: Date.parse(row.timestamp) || Date.now(),
|
|
210
|
-
},
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
return memories;
|
|
215
|
-
}
|
|
216
|
-
export function markAsDreamed(memoryIds) {
|
|
217
|
-
if (memoryIds.length === 0)
|
|
218
|
-
return;
|
|
219
|
-
const db = getDb();
|
|
220
|
-
const placeholders = memoryIds.map(() => "?").join(",");
|
|
221
|
-
db.prepare(`UPDATE deep_memories
|
|
222
|
-
SET dreamed = 1, dream_date = ?
|
|
223
|
-
WHERE id IN (${placeholders})`).run(new Date().toISOString(), ...memoryIds);
|
|
224
|
-
}
|
|
225
|
-
export function deepMemoryStats() {
|
|
226
|
-
const db = getDb();
|
|
227
|
-
// Exclude 'dream' and 'nightmare' from the general 'total_memories' and 'undreamed' count
|
|
228
|
-
// to avoid skewing the main memory metrics, but we still return their categories in the map.
|
|
229
|
-
const total = db
|
|
230
|
-
.prepare("SELECT COUNT(*) as c FROM deep_memories WHERE category NOT IN ('dream', 'nightmare')")
|
|
231
|
-
.get().c;
|
|
232
|
-
const undreamed = db
|
|
233
|
-
.prepare("SELECT COUNT(*) as c FROM deep_memories WHERE dreamed = 0 AND category NOT IN ('dream', 'nightmare')")
|
|
234
|
-
.get().c;
|
|
235
|
-
const categoryRows = db
|
|
236
|
-
.prepare("SELECT category, COUNT(*) as c FROM deep_memories GROUP BY category")
|
|
237
|
-
.all();
|
|
238
|
-
const categories = {};
|
|
239
|
-
for (const row of categoryRows) {
|
|
240
|
-
categories[row.category] = row.c;
|
|
241
|
-
}
|
|
242
|
-
return {
|
|
243
|
-
total_memories: total,
|
|
244
|
-
undreamed,
|
|
245
|
-
dreamed: total - undreamed,
|
|
246
|
-
categories,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Query deep memory with optional filters. Decrypts results, handles
|
|
251
|
-
* corruption gracefully, returns in chronological order.
|
|
252
|
-
*/
|
|
253
|
-
export function getRecentDeepMemories(options) {
|
|
254
|
-
const db = getDb();
|
|
255
|
-
const cipher = getCipher();
|
|
256
|
-
const conditions = [];
|
|
257
|
-
const params = [];
|
|
258
|
-
if (options?.categories && options.categories.length > 0) {
|
|
259
|
-
const placeholders = options.categories.map(() => "?").join(",");
|
|
260
|
-
conditions.push(`category IN (${placeholders})`);
|
|
261
|
-
params.push(...options.categories);
|
|
262
|
-
}
|
|
263
|
-
else {
|
|
264
|
-
// If no specific categories requested, exclude dreams/nightmares by default
|
|
265
|
-
conditions.push(`category NOT IN ('dream', 'nightmare')`);
|
|
266
|
-
}
|
|
267
|
-
if (options?.undreamedOnly) {
|
|
268
|
-
conditions.push("dreamed = 0");
|
|
269
|
-
}
|
|
270
|
-
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
271
|
-
const limitClause = options?.limit ? `LIMIT ?` : "";
|
|
272
|
-
if (options?.limit)
|
|
273
|
-
params.push(options.limit);
|
|
274
|
-
const query = `SELECT id, timestamp, category, encrypted_blob
|
|
275
|
-
FROM deep_memories ${where} ORDER BY timestamp DESC ${limitClause}`;
|
|
276
|
-
const rows = db.prepare(query).all(...params);
|
|
277
|
-
const memories = [];
|
|
278
|
-
for (const row of rows) {
|
|
279
|
-
try {
|
|
280
|
-
const decrypted = JSON.parse(cipher.decrypt(row.encrypted_blob));
|
|
281
|
-
memories.push({
|
|
282
|
-
id: row.id,
|
|
283
|
-
timestamp: row.timestamp,
|
|
284
|
-
category: row.category,
|
|
285
|
-
content: normalizeMemoryEntry(decrypted, row.timestamp),
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
catch {
|
|
289
|
-
memories.push({
|
|
290
|
-
id: row.id,
|
|
291
|
-
timestamp: row.timestamp,
|
|
292
|
-
category: "corrupted",
|
|
293
|
-
content: {
|
|
294
|
-
text_summary: "This memory could not be recovered.",
|
|
295
|
-
timestamp: Date.parse(row.timestamp) || Date.now(),
|
|
296
|
-
},
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
// Return in chronological order (oldest first)
|
|
301
|
-
return memories.reverse();
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Format decrypted memories as a text block for LLM prompts.
|
|
305
|
-
*
|
|
306
|
-
* Extracts `content.summary` when available, falls back to truncated JSON.
|
|
307
|
-
* Respects an approximate token budget (1 token ≈ 4 chars).
|
|
308
|
-
*/
|
|
309
|
-
export function formatDeepMemoryContext(memories, maxTokensApprox = DEEP_MEMORY_CONTEXT_TOKENS) {
|
|
310
|
-
const mems = memories ?? getRecentDeepMemories({ categories: ["interaction", "reflection"] });
|
|
311
|
-
if (mems.length === 0) {
|
|
312
|
-
return "No memories yet. This is my first day.";
|
|
313
|
-
}
|
|
314
|
-
const lines = [];
|
|
315
|
-
const charBudget = maxTokensApprox * 4;
|
|
316
|
-
let charCount = 0;
|
|
317
|
-
// Iterate from most recent to oldest
|
|
318
|
-
for (let i = mems.length - 1; i >= 0; i--) {
|
|
319
|
-
const mem = mems[i];
|
|
320
|
-
const entry = mem.content;
|
|
321
|
-
const summary = entry.text_summary || JSON.stringify(entry).slice(0, 200);
|
|
322
|
-
const parts = [];
|
|
323
|
-
if (entry.file_diffs && entry.file_diffs.length > 0) {
|
|
324
|
-
const diffStr = entry.file_diffs
|
|
325
|
-
.map((d) => `${d.path} (+${d.additions}/-${d.deletions})`)
|
|
326
|
-
.join(", ");
|
|
327
|
-
parts.push(`Files: ${diffStr}`);
|
|
328
|
-
}
|
|
329
|
-
if (entry.topics && entry.topics.length > 0) {
|
|
330
|
-
parts.push(`Topics: ${entry.topics.join(", ")}`);
|
|
331
|
-
}
|
|
332
|
-
if (entry.tool_calls && entry.tool_calls.length > 0) {
|
|
333
|
-
const toolStr = entry.tool_calls.map((t) => `${t.tool}×${t.count}`).join(", ");
|
|
334
|
-
parts.push(`Tools: ${toolStr}`);
|
|
335
|
-
}
|
|
336
|
-
const suffix = parts.length > 0 ? `\n ${parts.join(" | ")}` : "";
|
|
337
|
-
const line = `[${mem.timestamp.slice(0, 16)}] (${mem.category}) ${summary}${suffix}`;
|
|
338
|
-
if (charCount + line.length > charBudget) {
|
|
339
|
-
lines.unshift(`... (${mems.length - lines.length} older memories omitted)`);
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
|
-
lines.unshift(line);
|
|
343
|
-
charCount += line.length;
|
|
344
|
-
}
|
|
345
|
-
return lines.join("\n");
|
|
346
|
-
}
|
|
347
|
-
// ─── Dream Remembrance System ───────────────────────────────────────────────
|
|
348
|
-
/** Register a new dream. INSERT OR IGNORE (idempotent). */
|
|
349
|
-
export function registerDream(filename, title, dreamDate, options) {
|
|
350
|
-
const db = getDb();
|
|
351
|
-
const isNightmare = options?.isNightmare ? 1 : 0;
|
|
352
|
-
const isMetaSynthesis = options?.isMetaSynthesis ? 1 : 0;
|
|
353
|
-
const sourceFilenames = options?.sourceFilenames
|
|
354
|
-
? JSON.stringify(options.sourceFilenames)
|
|
355
|
-
: null;
|
|
356
|
-
const deepMemoryId = options?.deepMemoryId ?? null;
|
|
357
|
-
db.prepare(`INSERT OR IGNORE INTO dream_remembrances (filename, title, dream_date, is_nightmare, is_meta_synthesis, source_filenames, deep_memory_id)
|
|
358
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`).run(filename, title, dreamDate, isNightmare, isMetaSynthesis, sourceFilenames, deepMemoryId);
|
|
359
|
-
}
|
|
360
|
-
/** Increment remember_count for a dream that was selected. */
|
|
361
|
-
export function incrementRememberCount(filename) {
|
|
362
|
-
const db = getDb();
|
|
363
|
-
db.prepare(`UPDATE dream_remembrances SET remember_count = remember_count + 1 WHERE filename = ?`).run(filename);
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* Weighted random selection: score = 1/(count+1) * max(1, age_days).
|
|
367
|
-
* Fetch all rows from SQLite, compute scores in JS, do weighted pick.
|
|
368
|
-
* Returns filename and deep_memory_id, or null if table is empty.
|
|
369
|
-
*/
|
|
370
|
-
export function selectDreamToRemember(today) {
|
|
371
|
-
const db = getDb();
|
|
372
|
-
const rows = db
|
|
373
|
-
.prepare("SELECT filename, dream_date, remember_count, deep_memory_id FROM dream_remembrances")
|
|
374
|
-
.all();
|
|
375
|
-
if (rows.length === 0)
|
|
376
|
-
return null;
|
|
377
|
-
const todayMs = new Date(today).getTime();
|
|
378
|
-
const scoredRows = rows.map((row) => {
|
|
379
|
-
const dreamDateMs = new Date(row.dream_date).getTime();
|
|
380
|
-
const ageDays = Math.max(1, Math.ceil((todayMs - dreamDateMs) / (1000 * 60 * 60 * 24)));
|
|
381
|
-
const score = (1 / (row.remember_count + 1)) * ageDays;
|
|
382
|
-
return { ...row, score };
|
|
383
|
-
});
|
|
384
|
-
const totalScore = scoredRows.reduce((sum, row) => sum + row.score, 0);
|
|
385
|
-
let random = Math.random() * totalScore;
|
|
386
|
-
for (const row of scoredRows) {
|
|
387
|
-
random -= row.score;
|
|
388
|
-
if (random <= 0)
|
|
389
|
-
return { filename: row.filename, deep_memory_id: row.deep_memory_id };
|
|
390
|
-
}
|
|
391
|
-
const last = scoredRows[scoredRows.length - 1];
|
|
392
|
-
return { filename: last.filename, deep_memory_id: last.deep_memory_id };
|
|
393
|
-
}
|
|
394
|
-
/** For inspection/testing. */
|
|
395
|
-
export function getDreamRemembrances() {
|
|
396
|
-
const db = getDb();
|
|
397
|
-
return db
|
|
398
|
-
.prepare("SELECT filename, title, dream_date, remember_count, is_nightmare, is_meta_synthesis, source_filenames, deep_memory_id FROM dream_remembrances ORDER BY dream_date DESC")
|
|
399
|
-
.all();
|
|
400
|
-
}
|
|
401
|
-
export function insertDreamLineage(dreamFilename, parentMemoryIds, thematicKin, dominantConcepts) {
|
|
402
|
-
const db = getDb();
|
|
403
|
-
db.prepare(`INSERT INTO dream_lineage (dream_filename, parent_memory_ids, thematic_kin, dominant_concepts, created_at)
|
|
404
|
-
VALUES (?, ?, ?, ?, ?)`).run(dreamFilename, JSON.stringify(parentMemoryIds), JSON.stringify(thematicKin), JSON.stringify(dominantConcepts), new Date().toISOString());
|
|
405
|
-
}
|
|
406
|
-
export function getAllDreamLineage() {
|
|
407
|
-
const db = getDb();
|
|
408
|
-
return db
|
|
409
|
-
.prepare("SELECT * FROM dream_lineage ORDER BY created_at DESC")
|
|
410
|
-
.all();
|
|
411
|
-
}
|
|
412
|
-
export function getDreamLineageByFilename(filename) {
|
|
413
|
-
const db = getDb();
|
|
414
|
-
return (db.prepare("SELECT * FROM dream_lineage WHERE dream_filename = ?").get(filename) ?? null);
|
|
415
|
-
}
|
|
416
|
-
/**
|
|
417
|
-
* Find thematic kin for a dream by computing concept overlap with all prior dreams.
|
|
418
|
-
* Returns filenames of dreams with overlap >= threshold (default 0.3).
|
|
419
|
-
*/
|
|
420
|
-
export function findThematicKin(currentConcepts, currentFilename, threshold = 0.3) {
|
|
421
|
-
const rows = getAllDreamLineage();
|
|
422
|
-
const kin = [];
|
|
423
|
-
for (const row of rows) {
|
|
424
|
-
if (row.dream_filename === currentFilename)
|
|
425
|
-
continue;
|
|
426
|
-
const priorConcepts = row.dominant_concepts
|
|
427
|
-
? JSON.parse(row.dominant_concepts)
|
|
428
|
-
: [];
|
|
429
|
-
if (priorConcepts.length === 0 || currentConcepts.length === 0)
|
|
430
|
-
continue;
|
|
431
|
-
const priorSet = new Set(priorConcepts);
|
|
432
|
-
const currentSet = new Set(currentConcepts);
|
|
433
|
-
let intersection = 0;
|
|
434
|
-
for (const c of currentSet) {
|
|
435
|
-
if (priorSet.has(c))
|
|
436
|
-
intersection++;
|
|
437
|
-
}
|
|
438
|
-
const union = new Set([...currentSet, ...priorSet]).size;
|
|
439
|
-
const overlap = union === 0 ? 0 : intersection / union;
|
|
440
|
-
if (overlap >= threshold) {
|
|
441
|
-
kin.push({ filename: row.dream_filename, overlap });
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
return kin.sort((a, b) => b.overlap - a.overlap);
|
|
445
|
-
}
|
|
446
|
-
// ─── Store Helper ───────────────────────────────────────────────────────────
|
|
447
|
-
/**
|
|
448
|
-
* Store a structured MemoryEntry in encrypted deep memory.
|
|
449
|
-
*
|
|
450
|
-
* Accepts either a MemoryEntry directly, or a legacy (summary, fullContext)
|
|
451
|
-
* pair for backward compatibility.
|
|
452
|
-
*/
|
|
453
|
-
export function remember(summaryOrEntry, fullContextOrCategory, category = "interaction") {
|
|
454
|
-
if (typeof summaryOrEntry === "object") {
|
|
455
|
-
// New path: direct MemoryEntry
|
|
456
|
-
const cat = typeof fullContextOrCategory === "string" ? fullContextOrCategory : category;
|
|
457
|
-
storeDeepMemory(summaryOrEntry, cat);
|
|
458
|
-
}
|
|
459
|
-
else {
|
|
460
|
-
// Legacy path: summary + fullContext
|
|
461
|
-
const ctx = typeof fullContextOrCategory === "object" && fullContextOrCategory !== null
|
|
462
|
-
? fullContextOrCategory
|
|
463
|
-
: {};
|
|
464
|
-
storeDeepMemory({ ...ctx, summary: summaryOrEntry }, category);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
//# sourceMappingURL=memory.js.map
|