@xopcai/xopc 0.0.24 → 0.0.26
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/dist/extensions/feishu/xopc.extension.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/agents-Clv9i1Kb.js +216 -0
- package/dist/gateway/static/root/assets/agents-Clv9i1Kb.js.map +1 -0
- package/dist/gateway/static/root/assets/{apps-page-tZz69XM3.js → apps-page-DqclV-PP.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-tZz69XM3.js.map → apps-page-DqclV-PP.js.map} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-BAvk9-aK.js → channels-settings-CLyTYjrz.js} +3 -3
- package/dist/gateway/static/root/assets/{channels-settings-BAvk9-aK.js.map → channels-settings-CLyTYjrz.js.map} +1 -1
- package/dist/gateway/static/root/assets/cron-page-CU8lutMt.js +2 -0
- package/dist/gateway/static/root/assets/{cron-page-CANqvhK7.js.map → cron-page-CU8lutMt.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-utils-DyOO6TdN.js → cron-utils-_UjiWax6.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-utils-DyOO6TdN.js.map → cron-utils-_UjiWax6.js.map} +1 -1
- package/dist/gateway/static/root/assets/dist-Xqb4IGWC.js +2 -0
- package/dist/gateway/static/root/assets/{dist-Brod9LF3.js.map → dist-Xqb4IGWC.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-CDD7ozsC.js → extension-debug-page-CtTUkAmw.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-CDD7ozsC.js.map → extension-debug-page-CtTUkAmw.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-UUFMjoWf.js → extension-page-C-aQU8qR.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-UUFMjoWf.js.map → extension-page-C-aQU8qR.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CP9JNc4m.js → extension-settings-page-b0y9aY-q.js} +2 -2
- package/dist/gateway/static/root/assets/extension-settings-page-b0y9aY-q.js.map +1 -0
- package/dist/gateway/static/root/assets/index-DhSFfSNN.css +1 -0
- package/dist/gateway/static/root/assets/index-Gr2HWo-G.js +4734 -0
- package/dist/gateway/static/root/assets/index-Gr2HWo-G.js.map +1 -0
- package/dist/gateway/static/root/assets/logs-page-DRI33XK4.js +2 -0
- package/dist/gateway/static/root/assets/{logs-page-Cr0eCGb4.js.map → logs-page-DRI33XK4.js.map} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-Cryg-36Z.js +2 -0
- package/dist/gateway/static/root/assets/{sessions-page-DwLHN5GJ.js.map → sessions-page-Cryg-36Z.js.map} +1 -1
- package/dist/gateway/static/root/assets/settings-page-DFNKT9yg.js +2 -0
- package/dist/gateway/static/root/assets/settings-page-DFNKT9yg.js.map +1 -0
- package/dist/gateway/static/root/assets/skills-page-D4gfh0Ih.js +3 -0
- package/dist/gateway/static/root/assets/{skills-page-DgBYvH6B.js.map → skills-page-D4gfh0Ih.js.map} +1 -1
- package/dist/gateway/static/root/index.html +2 -2
- package/dist/package.js +1 -1
- package/dist/src/agent/memory/dreaming/config.d.ts +48 -0
- package/dist/src/agent/memory/dreaming/config.js +86 -0
- package/dist/src/agent/memory/dreaming/config.js.map +1 -0
- package/dist/src/agent/memory/dreaming/constants.d.ts +29 -0
- package/dist/src/agent/memory/dreaming/constants.js +38 -0
- package/dist/src/agent/memory/dreaming/constants.js.map +1 -0
- package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +21 -0
- package/dist/src/agent/memory/dreaming/deep-promotion.js +271 -0
- package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -0
- package/dist/src/agent/memory/dreaming/events.d.ts +36 -0
- package/dist/src/agent/memory/dreaming/events.js +44 -0
- package/dist/src/agent/memory/dreaming/events.js.map +1 -0
- package/dist/src/agent/memory/dreaming/last-run.d.ts +80 -0
- package/dist/src/agent/memory/dreaming/last-run.js +98 -0
- package/dist/src/agent/memory/dreaming/last-run.js.map +1 -0
- package/dist/src/agent/memory/dreaming/light-sweep.d.ts +19 -0
- package/dist/src/agent/memory/dreaming/light-sweep.js +328 -0
- package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -0
- package/dist/src/agent/memory/dreaming/preview.d.ts +28 -0
- package/dist/src/agent/memory/dreaming/preview.js +97 -0
- package/dist/src/agent/memory/dreaming/preview.js.map +1 -0
- package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +21 -0
- package/dist/src/agent/memory/dreaming/rem-patterns.js +286 -0
- package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -0
- package/dist/src/agent/memory/dreaming/short-term-store.d.ts +65 -0
- package/dist/src/agent/memory/dreaming/short-term-store.js +197 -0
- package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -0
- package/dist/src/agent/memory/dreaming/utils.d.ts +42 -0
- package/dist/src/agent/memory/dreaming/utils.js +141 -0
- package/dist/src/agent/memory/dreaming/utils.js.map +1 -0
- package/dist/src/agent/orchestration/agent-orchestrator.js +59 -0
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/service.d.ts +6 -0
- package/dist/src/agent/service.js +78 -0
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.d.ts +7 -0
- package/dist/src/agent/tools/dreaming-tool.js +102 -0
- package/dist/src/agent/tools/dreaming-tool.js.map +1 -0
- package/dist/src/agent/tools/factory.js +5 -0
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +1 -0
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/memory-tool.js +9 -2
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/config/schema.d.ts +93 -0
- package/dist/src/config/schema.js +42 -1
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +31 -0
- package/dist/src/gateway/hono/routes/config.js +48 -0
- package/dist/src/gateway/hono/routes/config.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.d.ts +3 -0
- package/dist/src/gateway/hono/routes/dreaming.js +288 -0
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -0
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +26 -1
- package/dist/src/gateway/hono/routes/models.js.map +1 -1
- package/dist/src/gateway/hono/routes/public-gateway.js +1 -0
- package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
- package/dist/src/gateway/lock.js +1 -1
- package/dist/src/gateway/service.js +7 -0
- package/dist/src/gateway/service.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-CiZMJZRp.js +0 -216
- package/dist/gateway/static/root/assets/agents-CiZMJZRp.js.map +0 -1
- package/dist/gateway/static/root/assets/cron-page-CANqvhK7.js +0 -2
- package/dist/gateway/static/root/assets/dist-Brod9LF3.js +0 -2
- package/dist/gateway/static/root/assets/extension-settings-page-CP9JNc4m.js.map +0 -1
- package/dist/gateway/static/root/assets/index-BZvlG48D.js +0 -150
- package/dist/gateway/static/root/assets/index-BZvlG48D.js.map +0 -1
- package/dist/gateway/static/root/assets/index-DxkgyT8R.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-Cr0eCGb4.js +0 -2
- package/dist/gateway/static/root/assets/sessions-page-DwLHN5GJ.js +0 -2
- package/dist/gateway/static/root/assets/settings-page-B3O3R0E4.js +0 -2
- package/dist/gateway/static/root/assets/settings-page-B3O3R0E4.js.map +0 -1
- package/dist/gateway/static/root/assets/skills-page-DgBYvH6B.js +0 -3
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { DEFAULT_DEEP_CRON, DEFAULT_LIGHT_CRON, DEFAULT_REM_CRON } from "./constants.js";
|
|
2
|
+
//#region src/agent/memory/dreaming/config.ts
|
|
3
|
+
function clampScore(value, fallback) {
|
|
4
|
+
if (!Number.isFinite(value)) return fallback;
|
|
5
|
+
return Math.max(0, Math.min(1, value));
|
|
6
|
+
}
|
|
7
|
+
function toPositiveInt(value, fallback) {
|
|
8
|
+
const num = typeof value === "string" ? Number(value) : Number(value);
|
|
9
|
+
if (!Number.isFinite(num)) return fallback;
|
|
10
|
+
const floored = Math.floor(num);
|
|
11
|
+
return floored > 0 ? floored : fallback;
|
|
12
|
+
}
|
|
13
|
+
function toNonNegInt(value, fallback) {
|
|
14
|
+
const num = typeof value === "string" ? Number(value) : Number(value);
|
|
15
|
+
if (!Number.isFinite(num)) return fallback;
|
|
16
|
+
const floored = Math.floor(num);
|
|
17
|
+
return floored >= 0 ? floored : fallback;
|
|
18
|
+
}
|
|
19
|
+
function trimmedStringOr(value, fallback) {
|
|
20
|
+
return typeof value === "string" && value.trim() ? value.trim() : fallback;
|
|
21
|
+
}
|
|
22
|
+
function optionalTrimmedString(value) {
|
|
23
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Resolve the full three-phase dreaming config from the app Config.
|
|
27
|
+
*
|
|
28
|
+
* Reads through `any` so it can ship independently of the schema evolution.
|
|
29
|
+
* Expected shape: `agents.defaults.memory.dreaming.{ enabled, frequency, timezone, phases.{light,deep,rem}.* }`
|
|
30
|
+
*/
|
|
31
|
+
function resolveDreamingConfig(cfg) {
|
|
32
|
+
const dreaming = cfg?.agents?.defaults?.memory?.dreaming;
|
|
33
|
+
const enabled = dreaming?.enabled === true;
|
|
34
|
+
const frequency = trimmedStringOr(dreaming?.frequency, DEFAULT_DEEP_CRON);
|
|
35
|
+
const timezone = optionalTrimmedString(dreaming?.timezone);
|
|
36
|
+
const lightRaw = dreaming?.phases?.light ?? {};
|
|
37
|
+
const light = {
|
|
38
|
+
enabled: enabled && lightRaw?.enabled !== false,
|
|
39
|
+
cron: trimmedStringOr(lightRaw?.cron, DEFAULT_LIGHT_CRON),
|
|
40
|
+
lookbackDays: toPositiveInt(lightRaw?.lookbackDays, 2),
|
|
41
|
+
limit: toNonNegInt(lightRaw?.limit, 100),
|
|
42
|
+
dedupeSimilarity: clampScore(Number(lightRaw?.dedupeSimilarity), .9)
|
|
43
|
+
};
|
|
44
|
+
const deepRaw = dreaming?.phases?.deep ?? {};
|
|
45
|
+
const deep = {
|
|
46
|
+
enabled: enabled && deepRaw?.enabled !== false,
|
|
47
|
+
cron: trimmedStringOr(deepRaw?.cron, frequency),
|
|
48
|
+
minScore: clampScore(Number(deepRaw?.minScore), .8),
|
|
49
|
+
minRecallCount: toPositiveInt(deepRaw?.minRecallCount, 3),
|
|
50
|
+
minUniqueQueries: toPositiveInt(deepRaw?.minUniqueQueries, 3),
|
|
51
|
+
limit: toNonNegInt(deepRaw?.limit, 10),
|
|
52
|
+
recencyHalfLifeDays: toPositiveInt(deepRaw?.recencyHalfLifeDays, 14),
|
|
53
|
+
maxAgeDays: toPositiveInt(deepRaw?.maxAgeDays, 30)
|
|
54
|
+
};
|
|
55
|
+
const remRaw = dreaming?.phases?.rem ?? {};
|
|
56
|
+
const rem = {
|
|
57
|
+
enabled: enabled && remRaw?.enabled !== false,
|
|
58
|
+
cron: trimmedStringOr(remRaw?.cron, DEFAULT_REM_CRON),
|
|
59
|
+
lookbackDays: toPositiveInt(remRaw?.lookbackDays, 7),
|
|
60
|
+
limit: toNonNegInt(remRaw?.limit, 10),
|
|
61
|
+
minPatternStrength: clampScore(Number(remRaw?.minPatternStrength), .75)
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
enabled,
|
|
65
|
+
frequency,
|
|
66
|
+
...timezone ? { timezone } : {},
|
|
67
|
+
phases: {
|
|
68
|
+
light,
|
|
69
|
+
deep,
|
|
70
|
+
rem
|
|
71
|
+
},
|
|
72
|
+
deep
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/** Get the cron expression for a specific phase from resolved config. */
|
|
76
|
+
function getPhaseCron(config, phase) {
|
|
77
|
+
return config.phases[phase].cron;
|
|
78
|
+
}
|
|
79
|
+
/** Check if a specific phase is enabled (global + phase-level). */
|
|
80
|
+
function isPhaseEnabled(config, phase) {
|
|
81
|
+
return config.enabled && config.phases[phase].enabled;
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { getPhaseCron, isPhaseEnabled, resolveDreamingConfig };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","names":["anyCfg"],"sources":["../../../../../src/agent/memory/dreaming/config.ts"],"sourcesContent":["import type { Config } from '../../../config/schema.js';\nimport {\n DEFAULT_DEEP_CRON,\n DEFAULT_LIGHT_CRON,\n DEFAULT_MAX_AGE_DAYS,\n DEFAULT_RECENCY_HALF_LIFE_DAYS,\n DEFAULT_REM_CRON,\n type DreamingPhaseId,\n} from './constants.js';\n\n// ── Phase config types ─────────────────────────────────────────────────\n\nexport type DreamingLightConfig = {\n enabled: boolean;\n cron: string;\n lookbackDays: number;\n limit: number;\n dedupeSimilarity: number;\n};\n\nexport type DreamingDeepConfig = {\n enabled: boolean;\n cron: string;\n minScore: number;\n minRecallCount: number;\n minUniqueQueries: number;\n limit: number;\n recencyHalfLifeDays: number;\n maxAgeDays: number;\n};\n\nexport type DreamingRemConfig = {\n enabled: boolean;\n cron: string;\n lookbackDays: number;\n limit: number;\n minPatternStrength: number;\n};\n\nexport type DreamingResolvedConfig = {\n enabled: boolean;\n frequency: string;\n timezone?: string;\n phases: {\n light: DreamingLightConfig;\n deep: DreamingDeepConfig;\n rem: DreamingRemConfig;\n };\n deep: DreamingDeepConfig;\n};\n\n// ── Helpers ────────────────────────────────────────────────────────────\n\nfunction clampScore(value: number, fallback: number): number {\n if (!Number.isFinite(value)) return fallback;\n return Math.max(0, Math.min(1, value));\n}\n\nfunction toPositiveInt(value: unknown, fallback: number): number {\n const num = typeof value === 'string' ? Number(value) : Number(value);\n if (!Number.isFinite(num)) return fallback;\n const floored = Math.floor(num);\n return floored > 0 ? floored : fallback;\n}\n\nfunction toNonNegInt(value: unknown, fallback: number): number {\n const num = typeof value === 'string' ? Number(value) : Number(value);\n if (!Number.isFinite(num)) return fallback;\n const floored = Math.floor(num);\n return floored >= 0 ? floored : fallback;\n}\n\nfunction trimmedStringOr(value: unknown, fallback: string): string {\n return typeof value === 'string' && value.trim() ? value.trim() : fallback;\n}\n\nfunction optionalTrimmedString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\n// ── Resolver ───────────────────────────────────────────────────────────\n\n/**\n * Resolve the full three-phase dreaming config from the app Config.\n *\n * Reads through `any` so it can ship independently of the schema evolution.\n * Expected shape: `agents.defaults.memory.dreaming.{ enabled, frequency, timezone, phases.{light,deep,rem}.* }`\n */\nexport function resolveDreamingConfig(cfg: Config | undefined): DreamingResolvedConfig {\n const anyCfg = cfg as any;\n const dreaming = anyCfg?.agents?.defaults?.memory?.dreaming;\n const enabled = dreaming?.enabled === true;\n\n const frequency = trimmedStringOr(dreaming?.frequency, DEFAULT_DEEP_CRON);\n const timezone = optionalTrimmedString(dreaming?.timezone);\n\n // ── Light phase ────────────────────────────────────────────────────\n const lightRaw = dreaming?.phases?.light ?? {};\n const light: DreamingLightConfig = {\n enabled: enabled && lightRaw?.enabled !== false,\n cron: trimmedStringOr(lightRaw?.cron, DEFAULT_LIGHT_CRON),\n lookbackDays: toPositiveInt(lightRaw?.lookbackDays, 2),\n limit: toNonNegInt(lightRaw?.limit, 100),\n dedupeSimilarity: clampScore(Number(lightRaw?.dedupeSimilarity), 0.9),\n };\n\n // ── Deep phase ─────────────────────────────────────────────────────\n const deepRaw = dreaming?.phases?.deep ?? {};\n const deep: DreamingDeepConfig = {\n enabled: enabled && deepRaw?.enabled !== false,\n cron: trimmedStringOr(deepRaw?.cron, frequency),\n minScore: clampScore(Number(deepRaw?.minScore), 0.8),\n minRecallCount: toPositiveInt(deepRaw?.minRecallCount, 3),\n minUniqueQueries: toPositiveInt(deepRaw?.minUniqueQueries, 3),\n limit: toNonNegInt(deepRaw?.limit, 10),\n recencyHalfLifeDays: toPositiveInt(deepRaw?.recencyHalfLifeDays, DEFAULT_RECENCY_HALF_LIFE_DAYS),\n maxAgeDays: toPositiveInt(deepRaw?.maxAgeDays, DEFAULT_MAX_AGE_DAYS),\n };\n\n // ── REM phase ──────────────────────────────────────────────────────\n const remRaw = dreaming?.phases?.rem ?? {};\n const rem: DreamingRemConfig = {\n enabled: enabled && remRaw?.enabled !== false,\n cron: trimmedStringOr(remRaw?.cron, DEFAULT_REM_CRON),\n lookbackDays: toPositiveInt(remRaw?.lookbackDays, 7),\n limit: toNonNegInt(remRaw?.limit, 10),\n minPatternStrength: clampScore(Number(remRaw?.minPatternStrength), 0.75),\n };\n\n return {\n enabled,\n frequency,\n ...(timezone ? { timezone } : {}),\n phases: { light, deep, rem },\n deep,\n };\n}\n\n/** Get the cron expression for a specific phase from resolved config. */\nexport function getPhaseCron(config: DreamingResolvedConfig, phase: DreamingPhaseId): string {\n return config.phases[phase].cron;\n}\n\n/** Check if a specific phase is enabled (global + phase-level). */\nexport function isPhaseEnabled(config: DreamingResolvedConfig, phase: DreamingPhaseId): boolean {\n return config.enabled && config.phases[phase].enabled;\n}\n\n"],"mappings":";;AAqDA,SAAS,WAAW,OAAe,UAA0B;AAC3D,KAAI,CAAC,OAAO,SAAS,MAAM,CAAE,QAAO;AACpC,QAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC;;AAGxC,SAAS,cAAc,OAAgB,UAA0B;CAC/D,MAAM,MAAM,OAAO,UAAU,WAAW,OAAO,MAAM,GAAG,OAAO,MAAM;AACrE,KAAI,CAAC,OAAO,SAAS,IAAI,CAAE,QAAO;CAClC,MAAM,UAAU,KAAK,MAAM,IAAI;AAC/B,QAAO,UAAU,IAAI,UAAU;;AAGjC,SAAS,YAAY,OAAgB,UAA0B;CAC7D,MAAM,MAAM,OAAO,UAAU,WAAW,OAAO,MAAM,GAAG,OAAO,MAAM;AACrE,KAAI,CAAC,OAAO,SAAS,IAAI,CAAE,QAAO;CAClC,MAAM,UAAU,KAAK,MAAM,IAAI;AAC/B,QAAO,WAAW,IAAI,UAAU;;AAGlC,SAAS,gBAAgB,OAAgB,UAA0B;AACjE,QAAO,OAAO,UAAU,YAAY,MAAM,MAAM,GAAG,MAAM,MAAM,GAAG;;AAGpE,SAAS,sBAAsB,OAAoC;AACjE,QAAO,OAAO,UAAU,YAAY,MAAM,MAAM,GAAG,MAAM,MAAM,GAAG,KAAA;;;;;;;;AAWpE,SAAgB,sBAAsB,KAAiD;CAErF,MAAM,WAAWA,KAAQ,QAAQ,UAAU,QAAQ;CACnD,MAAM,UAAU,UAAU,YAAY;CAEtC,MAAM,YAAY,gBAAgB,UAAU,WAAW,kBAAkB;CACzE,MAAM,WAAW,sBAAsB,UAAU,SAAS;CAG1D,MAAM,WAAW,UAAU,QAAQ,SAAS,EAAE;CAC9C,MAAM,QAA6B;EACjC,SAAS,WAAW,UAAU,YAAY;EAC1C,MAAM,gBAAgB,UAAU,MAAM,mBAAmB;EACzD,cAAc,cAAc,UAAU,cAAc,EAAE;EACtD,OAAO,YAAY,UAAU,OAAO,IAAI;EACxC,kBAAkB,WAAW,OAAO,UAAU,iBAAiB,EAAE,GAAI;EACtE;CAGD,MAAM,UAAU,UAAU,QAAQ,QAAQ,EAAE;CAC5C,MAAM,OAA2B;EAC/B,SAAS,WAAW,SAAS,YAAY;EACzC,MAAM,gBAAgB,SAAS,MAAM,UAAU;EAC/C,UAAU,WAAW,OAAO,SAAS,SAAS,EAAE,GAAI;EACpD,gBAAgB,cAAc,SAAS,gBAAgB,EAAE;EACzD,kBAAkB,cAAc,SAAS,kBAAkB,EAAE;EAC7D,OAAO,YAAY,SAAS,OAAO,GAAG;EACtC,qBAAqB,cAAc,SAAS,qBAAA,GAAoD;EAChG,YAAY,cAAc,SAAS,YAAA,GAAiC;EACrE;CAGD,MAAM,SAAS,UAAU,QAAQ,OAAO,EAAE;CAC1C,MAAM,MAAyB;EAC7B,SAAS,WAAW,QAAQ,YAAY;EACxC,MAAM,gBAAgB,QAAQ,MAAM,iBAAiB;EACrD,cAAc,cAAc,QAAQ,cAAc,EAAE;EACpD,OAAO,YAAY,QAAQ,OAAO,GAAG;EACrC,oBAAoB,WAAW,OAAO,QAAQ,mBAAmB,EAAE,IAAK;EACzE;AAED,QAAO;EACL;EACA;EACA,GAAI,WAAW,EAAE,UAAU,GAAG,EAAE;EAChC,QAAQ;GAAE;GAAO;GAAM;GAAK;EAC5B;EACD;;;AAIH,SAAgB,aAAa,QAAgC,OAAgC;AAC3F,QAAO,OAAO,OAAO,OAAO;;;AAI9B,SAAgB,eAAe,QAAgC,OAAiC;AAC9F,QAAO,OAAO,WAAW,OAAO,OAAO,OAAO"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type DreamingPhaseId = 'light' | 'deep' | 'rem';
|
|
2
|
+
export declare const DREAMING_PHASES: readonly DreamingPhaseId[];
|
|
3
|
+
export declare const DREAMING_SWEEP_TOKEN = "__xopc_memory_dreaming_sweep__";
|
|
4
|
+
export declare const DREAMING_LIGHT_SWEEP_TOKEN = "__xopc_memory_dreaming_light_sweep__";
|
|
5
|
+
export declare const DREAMING_REM_SWEEP_TOKEN = "__xopc_memory_dreaming_rem_sweep__";
|
|
6
|
+
export declare const DREAMING_CRON_TAG = "[managed-by=xopc.memory.dreaming]";
|
|
7
|
+
export declare const DREAMING_CRON_NAME = "Memory Dreaming - Deep Promotion";
|
|
8
|
+
export declare const DREAMING_LIGHT_CRON_NAME = "Memory Dreaming - Light Sweep";
|
|
9
|
+
export declare const DREAMING_REM_CRON_NAME = "Memory Dreaming - REM Patterns";
|
|
10
|
+
export declare const DEFAULT_DEEP_CRON = "0 3 * * *";
|
|
11
|
+
export declare const DEFAULT_LIGHT_CRON = "0 */6 * * *";
|
|
12
|
+
export declare const DEFAULT_REM_CRON = "0 5 * * 0";
|
|
13
|
+
export declare const DEFAULT_RECENCY_HALF_LIFE_DAYS = 14;
|
|
14
|
+
export declare const DEFAULT_MAX_AGE_DAYS = 30;
|
|
15
|
+
/** Milliseconds in one day (used for time-decay calculations). */
|
|
16
|
+
export declare const MS_PER_DAY = 86400000;
|
|
17
|
+
/** Weight applied to recall-count reinforcement (logarithmic boost). */
|
|
18
|
+
export declare const REINFORCEMENT_WEIGHT = 0.12;
|
|
19
|
+
/** Weight applied to signal-diversity bonus. */
|
|
20
|
+
export declare const DIVERSITY_WEIGHT = 0.08;
|
|
21
|
+
/** Number of signal dimensions used for diversity calculation. */
|
|
22
|
+
export declare const DIVERSITY_DIMENSION_COUNT = 4;
|
|
23
|
+
export declare const DREAMING_DIR_RELATIVE: string;
|
|
24
|
+
export declare const SHORT_TERM_RECALL_STORE_RELATIVE: string;
|
|
25
|
+
export declare const SHORT_TERM_PROMOTION_LOCK_RELATIVE: string;
|
|
26
|
+
export declare const DREAMING_LAST_RUN_RELATIVE: string;
|
|
27
|
+
export declare const DREAMING_EVENTS_LOG_RELATIVE: string;
|
|
28
|
+
export declare const MEMORY_MD_FILENAME = "MEMORY.md";
|
|
29
|
+
export declare const DREAMS_MD_FILENAME = "DREAMS.md";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
//#region src/agent/memory/dreaming/constants.ts
|
|
3
|
+
const DREAMING_PHASES = [
|
|
4
|
+
"light",
|
|
5
|
+
"deep",
|
|
6
|
+
"rem"
|
|
7
|
+
];
|
|
8
|
+
const DREAMING_SWEEP_TOKEN = "__xopc_memory_dreaming_sweep__";
|
|
9
|
+
const DREAMING_LIGHT_SWEEP_TOKEN = "__xopc_memory_dreaming_light_sweep__";
|
|
10
|
+
const DREAMING_REM_SWEEP_TOKEN = "__xopc_memory_dreaming_rem_sweep__";
|
|
11
|
+
const DREAMING_CRON_TAG = "[managed-by=xopc.memory.dreaming]";
|
|
12
|
+
const DREAMING_CRON_NAME = "Memory Dreaming - Deep Promotion";
|
|
13
|
+
const DREAMING_LIGHT_CRON_NAME = "Memory Dreaming - Light Sweep";
|
|
14
|
+
const DREAMING_REM_CRON_NAME = "Memory Dreaming - REM Patterns";
|
|
15
|
+
const DEFAULT_DEEP_CRON = "0 3 * * *";
|
|
16
|
+
const DEFAULT_LIGHT_CRON = "0 */6 * * *";
|
|
17
|
+
const DEFAULT_REM_CRON = "0 5 * * 0";
|
|
18
|
+
const DEFAULT_RECENCY_HALF_LIFE_DAYS = 14;
|
|
19
|
+
const DEFAULT_MAX_AGE_DAYS = 30;
|
|
20
|
+
/** Milliseconds in one day (used for time-decay calculations). */
|
|
21
|
+
const MS_PER_DAY = 864e5;
|
|
22
|
+
/** Weight applied to recall-count reinforcement (logarithmic boost). */
|
|
23
|
+
const REINFORCEMENT_WEIGHT = .12;
|
|
24
|
+
/** Weight applied to signal-diversity bonus. */
|
|
25
|
+
const DIVERSITY_WEIGHT = .08;
|
|
26
|
+
/** Number of signal dimensions used for diversity calculation. */
|
|
27
|
+
const DIVERSITY_DIMENSION_COUNT = 4;
|
|
28
|
+
const DREAMING_DIR_RELATIVE = path.join("memory", ".dreams");
|
|
29
|
+
const SHORT_TERM_RECALL_STORE_RELATIVE = path.join(DREAMING_DIR_RELATIVE, "short-term-recall.json");
|
|
30
|
+
const SHORT_TERM_PROMOTION_LOCK_RELATIVE = path.join(DREAMING_DIR_RELATIVE, "short-term-promotion.lock");
|
|
31
|
+
const DREAMING_LAST_RUN_RELATIVE = path.join(DREAMING_DIR_RELATIVE, "last-run.json");
|
|
32
|
+
const DREAMING_EVENTS_LOG_RELATIVE = path.join(DREAMING_DIR_RELATIVE, "events.jsonl");
|
|
33
|
+
const MEMORY_MD_FILENAME = "MEMORY.md";
|
|
34
|
+
const DREAMS_MD_FILENAME = "DREAMS.md";
|
|
35
|
+
//#endregion
|
|
36
|
+
export { DEFAULT_DEEP_CRON, DEFAULT_LIGHT_CRON, DEFAULT_MAX_AGE_DAYS, DEFAULT_RECENCY_HALF_LIFE_DAYS, DEFAULT_REM_CRON, DIVERSITY_DIMENSION_COUNT, DIVERSITY_WEIGHT, DREAMING_CRON_NAME, DREAMING_CRON_TAG, DREAMING_DIR_RELATIVE, DREAMING_EVENTS_LOG_RELATIVE, DREAMING_LAST_RUN_RELATIVE, DREAMING_LIGHT_CRON_NAME, DREAMING_LIGHT_SWEEP_TOKEN, DREAMING_PHASES, DREAMING_REM_CRON_NAME, DREAMING_REM_SWEEP_TOKEN, DREAMING_SWEEP_TOKEN, DREAMS_MD_FILENAME, MEMORY_MD_FILENAME, MS_PER_DAY, REINFORCEMENT_WEIGHT, SHORT_TERM_PROMOTION_LOCK_RELATIVE, SHORT_TERM_RECALL_STORE_RELATIVE };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","names":[],"sources":["../../../../../src/agent/memory/dreaming/constants.ts"],"sourcesContent":["import path from 'node:path';\n\n// ── Phase identifiers ──────────────────────────────────────────────────\n\nexport type DreamingPhaseId = 'light' | 'deep' | 'rem';\n\nexport const DREAMING_PHASES: readonly DreamingPhaseId[] = ['light', 'deep', 'rem'] as const;\n\n// ── Sweep tokens (used in cron payloads to trigger each phase) ─────────\n\nexport const DREAMING_SWEEP_TOKEN = '__xopc_memory_dreaming_sweep__';\nexport const DREAMING_LIGHT_SWEEP_TOKEN = '__xopc_memory_dreaming_light_sweep__';\nexport const DREAMING_REM_SWEEP_TOKEN = '__xopc_memory_dreaming_rem_sweep__';\n\n// ── Cron job metadata ──────────────────────────────────────────────────\n\nexport const DREAMING_CRON_TAG = '[managed-by=xopc.memory.dreaming]';\n\nexport const DREAMING_CRON_NAME = 'Memory Dreaming - Deep Promotion';\nexport const DREAMING_LIGHT_CRON_NAME = 'Memory Dreaming - Light Sweep';\nexport const DREAMING_REM_CRON_NAME = 'Memory Dreaming - REM Patterns';\n\n// ── Default cron schedules ─────────────────────────────────────────────\n\nexport const DEFAULT_DEEP_CRON = '0 3 * * *';\nexport const DEFAULT_LIGHT_CRON = '0 */6 * * *';\nexport const DEFAULT_REM_CRON = '0 5 * * 0';\n\n// ── Time-decay defaults ────────────────────────────────────────────────\n\nexport const DEFAULT_RECENCY_HALF_LIFE_DAYS = 14;\nexport const DEFAULT_MAX_AGE_DAYS = 30;\n\n// ── Scoring weights ────────────────────────────────────────────────────\n\n/** Milliseconds in one day (used for time-decay calculations). */\nexport const MS_PER_DAY = 86_400_000;\n\n/** Weight applied to recall-count reinforcement (logarithmic boost). */\nexport const REINFORCEMENT_WEIGHT = 0.12;\n\n/** Weight applied to signal-diversity bonus. */\nexport const DIVERSITY_WEIGHT = 0.08;\n\n/** Number of signal dimensions used for diversity calculation. */\nexport const DIVERSITY_DIMENSION_COUNT = 4;\n\n// ── File paths ─────────────────────────────────────────────────────────\n\nexport const DREAMING_DIR_RELATIVE = path.join('memory', '.dreams');\nexport const SHORT_TERM_RECALL_STORE_RELATIVE = path.join(DREAMING_DIR_RELATIVE, 'short-term-recall.json');\nexport const SHORT_TERM_PROMOTION_LOCK_RELATIVE = path.join(\n DREAMING_DIR_RELATIVE,\n 'short-term-promotion.lock',\n);\nexport const DREAMING_LAST_RUN_RELATIVE = path.join(DREAMING_DIR_RELATIVE, 'last-run.json');\nexport const DREAMING_EVENTS_LOG_RELATIVE = path.join(DREAMING_DIR_RELATIVE, 'events.jsonl');\n\nexport const MEMORY_MD_FILENAME = 'MEMORY.md';\nexport const DREAMS_MD_FILENAME = 'DREAMS.md';\n\n"],"mappings":";;AAMA,MAAa,kBAA8C;CAAC;CAAS;CAAQ;CAAM;AAInF,MAAa,uBAAuB;AACpC,MAAa,6BAA6B;AAC1C,MAAa,2BAA2B;AAIxC,MAAa,oBAAoB;AAEjC,MAAa,qBAAqB;AAClC,MAAa,2BAA2B;AACxC,MAAa,yBAAyB;AAItC,MAAa,oBAAoB;AACjC,MAAa,qBAAqB;AAClC,MAAa,mBAAmB;AAIhC,MAAa,iCAAiC;AAC9C,MAAa,uBAAuB;;AAKpC,MAAa,aAAa;;AAG1B,MAAa,uBAAuB;;AAGpC,MAAa,mBAAmB;;AAGhC,MAAa,4BAA4B;AAIzC,MAAa,wBAAwB,KAAK,KAAK,UAAU,UAAU;AACnE,MAAa,mCAAmC,KAAK,KAAK,uBAAuB,yBAAyB;AAC1G,MAAa,qCAAqC,KAAK,KACrD,uBACA,4BACD;AACD,MAAa,6BAA6B,KAAK,KAAK,uBAAuB,gBAAgB;AAC3F,MAAa,+BAA+B,KAAK,KAAK,uBAAuB,eAAe;AAE5F,MAAa,qBAAqB;AAClC,MAAa,qBAAqB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type DreamingStoreEntry } from './short-term-store.js';
|
|
2
|
+
import type { DreamingDeepConfig } from './config.js';
|
|
3
|
+
export type { DreamingDeepConfig } from './config.js';
|
|
4
|
+
export type DreamingPromotionCandidate = DreamingStoreEntry & {
|
|
5
|
+
avgScore: number;
|
|
6
|
+
/** Time-decay-adjusted final score used for ranking. */
|
|
7
|
+
score: number;
|
|
8
|
+
/** Raw recency decay multiplier (0–1). */
|
|
9
|
+
recencyDecay: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function runDreamingDeepPromotion(params: {
|
|
12
|
+
workspaceDir: string;
|
|
13
|
+
config?: Partial<DreamingDeepConfig>;
|
|
14
|
+
now?: Date;
|
|
15
|
+
}): Promise<{
|
|
16
|
+
ok: boolean;
|
|
17
|
+
reason: string;
|
|
18
|
+
candidates: number;
|
|
19
|
+
applied: number;
|
|
20
|
+
memoryPath: string;
|
|
21
|
+
}>;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { createLogger } from "../../../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../../../utils/logger.js";
|
|
3
|
+
import { MEMORY_MD_FILENAME } from "./constants.js";
|
|
4
|
+
import { clamp01, compareCandidatesByScore, computeCandidateScore, extractPromotionMarkers, isContaminatedSnippet, isExpiredEntry, isoDay, readFileLines, resolveDeepDefaults, sliceRange, snippetHash } from "./utils.js";
|
|
5
|
+
import { loadDreamingStore, saveDreamingStore, withDreamingPromotionLock } from "./short-term-store.js";
|
|
6
|
+
import { emptyDeepPhaseSkipped, writeDreamingDeepLastRun } from "./last-run.js";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import fs from "node:fs/promises";
|
|
9
|
+
//#region src/agent/memory/dreaming/deep-promotion.ts
|
|
10
|
+
init_logger();
|
|
11
|
+
const log = createLogger("Dreaming:Deep");
|
|
12
|
+
function markerForPromotion(key, hash) {
|
|
13
|
+
return `<!-- xopc-memory-promotion key="${key}" hash="${hash}" -->`;
|
|
14
|
+
}
|
|
15
|
+
async function rehydrateSnippet(params) {
|
|
16
|
+
const lines = await readFileLines(path.join(params.workspaceDir, params.candidate.path));
|
|
17
|
+
if (!lines) return null;
|
|
18
|
+
const startLine = Math.max(1, Math.floor(params.candidate.startLine));
|
|
19
|
+
const endLine = Math.max(startLine, Math.floor(params.candidate.endLine));
|
|
20
|
+
const snippet = sliceRange(lines, startLine, endLine);
|
|
21
|
+
if (!snippet) return null;
|
|
22
|
+
return {
|
|
23
|
+
snippet,
|
|
24
|
+
startLine,
|
|
25
|
+
endLine
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function buildDeepLastRun(base) {
|
|
29
|
+
const durationMs = Math.max(0, Date.now() - base.t0);
|
|
30
|
+
return {
|
|
31
|
+
version: 2,
|
|
32
|
+
phase: "deep",
|
|
33
|
+
runId: base.runId,
|
|
34
|
+
startedAt: base.startedAt,
|
|
35
|
+
finishedAt: base.finishedAt,
|
|
36
|
+
durationMs,
|
|
37
|
+
ok: base.ok,
|
|
38
|
+
reason: base.reason,
|
|
39
|
+
config: base.config,
|
|
40
|
+
memoryPath: base.memoryPath,
|
|
41
|
+
...base.errorMessage ? { errorMessage: base.errorMessage } : {},
|
|
42
|
+
deep: base.deep
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async function runDreamingDeepPromotion(params) {
|
|
46
|
+
const cfg = resolveDeepDefaults(params.config);
|
|
47
|
+
const now = params.now ?? /* @__PURE__ */ new Date();
|
|
48
|
+
const startedAt = now.toISOString();
|
|
49
|
+
const runId = `${startedAt}:${process.pid}:${Math.random().toString(16).slice(2)}`;
|
|
50
|
+
const memoryPath = path.join(params.workspaceDir, MEMORY_MD_FILENAME);
|
|
51
|
+
const t0 = Date.now();
|
|
52
|
+
const earlyExitReason = !cfg.enabled ? "dreaming disabled" : cfg.limit === 0 ? "dreaming limit=0" : null;
|
|
53
|
+
if (earlyExitReason) {
|
|
54
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
55
|
+
const empty = emptyDeepPhaseSkipped();
|
|
56
|
+
await writeDreamingDeepLastRun({
|
|
57
|
+
workspaceDir: params.workspaceDir,
|
|
58
|
+
lastRun: buildDeepLastRun({
|
|
59
|
+
runId,
|
|
60
|
+
startedAt,
|
|
61
|
+
finishedAt,
|
|
62
|
+
t0,
|
|
63
|
+
ok: true,
|
|
64
|
+
reason: earlyExitReason,
|
|
65
|
+
config: cfg,
|
|
66
|
+
memoryPath,
|
|
67
|
+
deep: {
|
|
68
|
+
candidatesRanked: 0,
|
|
69
|
+
applied: 0,
|
|
70
|
+
skipped: empty
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
}).catch(() => void 0);
|
|
74
|
+
return {
|
|
75
|
+
ok: true,
|
|
76
|
+
reason: earlyExitReason,
|
|
77
|
+
candidates: 0,
|
|
78
|
+
applied: 0,
|
|
79
|
+
memoryPath
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const result = await withDreamingPromotionLock(params.workspaceDir, async () => {
|
|
84
|
+
const { store } = await loadDreamingStore({ workspaceDir: params.workspaceDir });
|
|
85
|
+
const nowMs = now.getTime();
|
|
86
|
+
const ranked = Object.values(store.entries ?? {}).filter((e) => {
|
|
87
|
+
if (!e || typeof e !== "object") return false;
|
|
88
|
+
if (e.promotedAt) return false;
|
|
89
|
+
if (!e.path || !e.path.startsWith("memory/")) return false;
|
|
90
|
+
if (e.recallCount < cfg.minRecallCount) return false;
|
|
91
|
+
if ((e.queryHashes?.length ?? 0) < cfg.minUniqueQueries) return false;
|
|
92
|
+
if (isExpiredEntry(e.lastRecalledAt, nowMs, cfg.maxAgeDays)) return false;
|
|
93
|
+
return clamp01(e.recallCount > 0 ? e.totalScore / e.recallCount : 0) >= cfg.minScore;
|
|
94
|
+
}).map((e) => {
|
|
95
|
+
const { avgScore, score, recencyDecay } = computeCandidateScore(e, nowMs, cfg.recencyHalfLifeDays);
|
|
96
|
+
return {
|
|
97
|
+
...e,
|
|
98
|
+
avgScore,
|
|
99
|
+
score,
|
|
100
|
+
recencyDecay
|
|
101
|
+
};
|
|
102
|
+
}).sort(compareCandidatesByScore).slice(0, cfg.limit);
|
|
103
|
+
if (ranked.length === 0) return {
|
|
104
|
+
ok: true,
|
|
105
|
+
reason: "no eligible candidates",
|
|
106
|
+
candidates: 0,
|
|
107
|
+
applied: 0,
|
|
108
|
+
memoryPath,
|
|
109
|
+
skipped: emptyDeepPhaseSkipped()
|
|
110
|
+
};
|
|
111
|
+
const existing = await fs.readFile(memoryPath, "utf-8").catch((err) => {
|
|
112
|
+
if (err?.code === "ENOENT") return "";
|
|
113
|
+
throw err;
|
|
114
|
+
});
|
|
115
|
+
const existingMarkers = extractPromotionMarkers(existing);
|
|
116
|
+
const appliedCandidates = [];
|
|
117
|
+
const skipped = emptyDeepPhaseSkipped();
|
|
118
|
+
for (const candidate of ranked) {
|
|
119
|
+
if (existingMarkers.keys.has(candidate.key)) {
|
|
120
|
+
skipped.alreadyPromotedKey += 1;
|
|
121
|
+
const entry = store.entries[candidate.key];
|
|
122
|
+
if (entry && !entry.promotedAt) entry.promotedAt = now.toISOString();
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const rehydrated = await rehydrateSnippet({
|
|
126
|
+
workspaceDir: params.workspaceDir,
|
|
127
|
+
candidate
|
|
128
|
+
});
|
|
129
|
+
if (!rehydrated) {
|
|
130
|
+
skipped.rehydrateFailed += 1;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (isContaminatedSnippet(rehydrated.snippet)) {
|
|
134
|
+
skipped.contaminated += 1;
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const hash = snippetHash(rehydrated.snippet);
|
|
138
|
+
if (existingMarkers.hashes.has(hash)) {
|
|
139
|
+
skipped.hashDuplicate += 1;
|
|
140
|
+
const entry = store.entries[candidate.key];
|
|
141
|
+
if (entry && !entry.promotedAt) entry.promotedAt = now.toISOString();
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
appliedCandidates.push({
|
|
145
|
+
key: candidate.key,
|
|
146
|
+
hash,
|
|
147
|
+
snippet: rehydrated.snippet,
|
|
148
|
+
path: candidate.path,
|
|
149
|
+
startLine: rehydrated.startLine,
|
|
150
|
+
endLine: rehydrated.endLine,
|
|
151
|
+
score: candidate.score,
|
|
152
|
+
recallCount: candidate.recallCount,
|
|
153
|
+
avgScore: candidate.avgScore
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (appliedCandidates.length === 0) {
|
|
157
|
+
await saveDreamingStore({
|
|
158
|
+
workspaceDir: params.workspaceDir,
|
|
159
|
+
store
|
|
160
|
+
});
|
|
161
|
+
return {
|
|
162
|
+
ok: true,
|
|
163
|
+
reason: "candidates were stale or already applied",
|
|
164
|
+
candidates: ranked.length,
|
|
165
|
+
applied: 0,
|
|
166
|
+
memoryPath,
|
|
167
|
+
skipped
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const day = isoDay(now);
|
|
171
|
+
const header = existing.trim().length > 0 ? "" : "# Long-Term Memory\n\n";
|
|
172
|
+
const sectionLines = [
|
|
173
|
+
"",
|
|
174
|
+
`## Promoted From Short-Term Memory (${day})`,
|
|
175
|
+
""
|
|
176
|
+
];
|
|
177
|
+
for (const c of appliedCandidates) {
|
|
178
|
+
const src = `${c.path}:${c.startLine}-${c.endLine}`;
|
|
179
|
+
sectionLines.push(markerForPromotion(c.key, c.hash));
|
|
180
|
+
sectionLines.push(`- ${c.snippet} [score=${c.score.toFixed(3)} recalls=${c.recallCount} avg=${c.avgScore.toFixed(3)} source=${src}]`);
|
|
181
|
+
}
|
|
182
|
+
sectionLines.push("");
|
|
183
|
+
const next = `${header}${existing.endsWith("\n") || existing.length === 0 ? existing : `${existing}\n`}${sectionLines.join("\n")}`;
|
|
184
|
+
await fs.writeFile(memoryPath, next, "utf-8");
|
|
185
|
+
const nowIso = now.toISOString();
|
|
186
|
+
for (const c of appliedCandidates) {
|
|
187
|
+
const entry = store.entries[c.key];
|
|
188
|
+
if (entry) {
|
|
189
|
+
entry.promotedAt = nowIso;
|
|
190
|
+
entry.snippet = c.snippet;
|
|
191
|
+
entry.startLine = c.startLine;
|
|
192
|
+
entry.endLine = c.endLine;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
store.updatedAt = nowIso;
|
|
196
|
+
await saveDreamingStore({
|
|
197
|
+
workspaceDir: params.workspaceDir,
|
|
198
|
+
store
|
|
199
|
+
});
|
|
200
|
+
log.info({
|
|
201
|
+
workspaceDir: params.workspaceDir,
|
|
202
|
+
candidates: ranked.length,
|
|
203
|
+
applied: appliedCandidates.length
|
|
204
|
+
}, "Dreaming deep promotion complete");
|
|
205
|
+
return {
|
|
206
|
+
ok: true,
|
|
207
|
+
reason: "applied promotions",
|
|
208
|
+
candidates: ranked.length,
|
|
209
|
+
applied: appliedCandidates.length,
|
|
210
|
+
memoryPath,
|
|
211
|
+
skipped
|
|
212
|
+
};
|
|
213
|
+
});
|
|
214
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
215
|
+
const empty = emptyDeepPhaseSkipped();
|
|
216
|
+
const resultSkipped = "skipped" in result ? result.skipped : empty;
|
|
217
|
+
await writeDreamingDeepLastRun({
|
|
218
|
+
workspaceDir: params.workspaceDir,
|
|
219
|
+
lastRun: buildDeepLastRun({
|
|
220
|
+
runId,
|
|
221
|
+
startedAt,
|
|
222
|
+
finishedAt,
|
|
223
|
+
t0,
|
|
224
|
+
ok: result.ok,
|
|
225
|
+
reason: result.reason,
|
|
226
|
+
config: cfg,
|
|
227
|
+
memoryPath: result.memoryPath,
|
|
228
|
+
deep: {
|
|
229
|
+
candidatesRanked: result.candidates,
|
|
230
|
+
applied: result.applied,
|
|
231
|
+
skipped: resultSkipped
|
|
232
|
+
}
|
|
233
|
+
})
|
|
234
|
+
}).catch(() => void 0);
|
|
235
|
+
return {
|
|
236
|
+
ok: result.ok,
|
|
237
|
+
reason: result.reason,
|
|
238
|
+
candidates: result.candidates,
|
|
239
|
+
applied: result.applied,
|
|
240
|
+
memoryPath: result.memoryPath
|
|
241
|
+
};
|
|
242
|
+
} catch (err) {
|
|
243
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
244
|
+
const em = err instanceof Error ? err.message : String(err);
|
|
245
|
+
const z = emptyDeepPhaseSkipped();
|
|
246
|
+
await writeDreamingDeepLastRun({
|
|
247
|
+
workspaceDir: params.workspaceDir,
|
|
248
|
+
lastRun: buildDeepLastRun({
|
|
249
|
+
runId,
|
|
250
|
+
startedAt,
|
|
251
|
+
finishedAt,
|
|
252
|
+
t0,
|
|
253
|
+
ok: false,
|
|
254
|
+
reason: "error",
|
|
255
|
+
config: cfg,
|
|
256
|
+
memoryPath,
|
|
257
|
+
errorMessage: em,
|
|
258
|
+
deep: {
|
|
259
|
+
candidatesRanked: 0,
|
|
260
|
+
applied: 0,
|
|
261
|
+
skipped: z
|
|
262
|
+
}
|
|
263
|
+
})
|
|
264
|
+
}).catch(() => void 0);
|
|
265
|
+
throw err;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
//#endregion
|
|
269
|
+
export { runDreamingDeepPromotion };
|
|
270
|
+
|
|
271
|
+
//# sourceMappingURL=deep-promotion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deep-promotion.js","names":[],"sources":["../../../../../src/agent/memory/dreaming/deep-promotion.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { createLogger } from '../../../utils/logger.js';\nimport { MEMORY_MD_FILENAME } from './constants.js';\nimport {\n loadDreamingStore,\n saveDreamingStore,\n withDreamingPromotionLock,\n type DreamingStoreEntry,\n} from './short-term-store.js';\nimport {\n DREAMING_LAST_RUN_FORMAT_VERSION,\n emptyDeepPhaseSkipped,\n writeDreamingDeepLastRun,\n type DreamingDeepLastRun,\n type DreamingDeepPhaseSkipped,\n} from './last-run.js';\nimport type { DreamingDeepConfig } from './config.js';\nimport {\n clamp01,\n compareCandidatesByScore,\n computeCandidateScore,\n extractPromotionMarkers,\n isContaminatedSnippet,\n isExpiredEntry,\n isoDay,\n readFileLines,\n resolveDeepDefaults,\n sliceRange,\n snippetHash,\n} from './utils.js';\n\nconst log = createLogger('Dreaming:Deep');\n\nexport type { DreamingDeepConfig } from './config.js';\n\nexport type DreamingPromotionCandidate = DreamingStoreEntry & {\n avgScore: number;\n /** Time-decay-adjusted final score used for ranking. */\n score: number;\n /** Raw recency decay multiplier (0–1). */\n recencyDecay: number;\n};\n\n\nfunction markerForPromotion(key: string, hash: string): string {\n // Quote values to allow spaces/colons in key.\n return `<!-- xopc-memory-promotion key=\"${key}\" hash=\"${hash}\" -->`;\n}\n\n\nasync function rehydrateSnippet(params: {\n workspaceDir: string;\n candidate: DreamingPromotionCandidate;\n}): Promise<{ snippet: string; startLine: number; endLine: number } | null> {\n const fullPath = path.join(params.workspaceDir, params.candidate.path);\n const lines = await readFileLines(fullPath);\n if (!lines) return null;\n\n const startLine = Math.max(1, Math.floor(params.candidate.startLine));\n const endLine = Math.max(startLine, Math.floor(params.candidate.endLine));\n const snippet = sliceRange(lines, startLine, endLine);\n if (!snippet) return null;\n return { snippet, startLine, endLine };\n}\n\n\nfunction buildDeepLastRun(base: {\n runId: string;\n startedAt: string;\n finishedAt: string;\n t0: number;\n ok: boolean;\n reason: string;\n config: DreamingDeepConfig;\n memoryPath: string;\n errorMessage?: string;\n deep: DreamingDeepLastRun['deep'];\n}): DreamingDeepLastRun {\n const durationMs = Math.max(0, Date.now() - base.t0);\n return {\n version: DREAMING_LAST_RUN_FORMAT_VERSION,\n phase: 'deep',\n runId: base.runId,\n startedAt: base.startedAt,\n finishedAt: base.finishedAt,\n durationMs,\n ok: base.ok,\n reason: base.reason,\n config: base.config,\n memoryPath: base.memoryPath,\n ...(base.errorMessage ? { errorMessage: base.errorMessage } : {}),\n deep: base.deep,\n };\n}\n\nexport async function runDreamingDeepPromotion(params: {\n workspaceDir: string;\n config?: Partial<DreamingDeepConfig>;\n now?: Date;\n}): Promise<{\n ok: boolean;\n reason: string;\n candidates: number;\n applied: number;\n memoryPath: string;\n}> {\n const cfg = resolveDeepDefaults(params.config);\n const now = params.now ?? new Date();\n const startedAt = now.toISOString();\n const runId = `${startedAt}:${process.pid}:${Math.random().toString(16).slice(2)}`;\n const memoryPath = path.join(params.workspaceDir, MEMORY_MD_FILENAME);\n const t0 = Date.now();\n\n // Early exit for disabled or zero-limit configurations.\n const earlyExitReason = !cfg.enabled ? 'dreaming disabled' : cfg.limit === 0 ? 'dreaming limit=0' : null;\n if (earlyExitReason) {\n const finishedAt = new Date().toISOString();\n const empty = emptyDeepPhaseSkipped();\n await writeDreamingDeepLastRun({\n workspaceDir: params.workspaceDir,\n lastRun: buildDeepLastRun({\n runId,\n startedAt,\n finishedAt,\n t0,\n ok: true,\n reason: earlyExitReason,\n config: cfg,\n memoryPath,\n deep: { candidatesRanked: 0, applied: 0, skipped: empty },\n }),\n }).catch(() => undefined);\n return { ok: true, reason: earlyExitReason, candidates: 0, applied: 0, memoryPath };\n }\n\n try {\n const result = await withDreamingPromotionLock(params.workspaceDir, async () => {\n const { store } = await loadDreamingStore({ workspaceDir: params.workspaceDir });\n\n const nowMs = now.getTime();\n\n const all = Object.values(store.entries ?? {}).filter((e): e is DreamingStoreEntry => {\n if (!e || typeof e !== 'object') return false;\n if (e.promotedAt) return false;\n if (!e.path || !e.path.startsWith('memory/')) return false;\n if (e.recallCount < cfg.minRecallCount) return false;\n // Require minimum unique queries to avoid single-query inflation.\n if ((e.queryHashes?.length ?? 0) < cfg.minUniqueQueries) return false;\n // Expire entries older than maxAgeDays since last recall.\n if (isExpiredEntry(e.lastRecalledAt, nowMs, cfg.maxAgeDays)) return false;\n const avg = e.recallCount > 0 ? e.totalScore / e.recallCount : 0;\n return clamp01(avg) >= cfg.minScore;\n });\n\n const ranked: DreamingPromotionCandidate[] = all\n .map((e) => {\n const { avgScore, score, recencyDecay } = computeCandidateScore(e, nowMs, cfg.recencyHalfLifeDays);\n return { ...e, avgScore, score, recencyDecay };\n })\n .sort(compareCandidatesByScore)\n .slice(0, cfg.limit);\n\n if (ranked.length === 0) {\n const z = emptyDeepPhaseSkipped();\n return { ok: true, reason: 'no eligible candidates', candidates: 0, applied: 0, memoryPath, skipped: z };\n }\n\n const existing = await fs.readFile(memoryPath, 'utf-8').catch((err: unknown) => {\n if ((err as NodeJS.ErrnoException | undefined)?.code === 'ENOENT') return '';\n throw err;\n });\n const existingMarkers = extractPromotionMarkers(existing);\n\n const appliedCandidates: Array<{\n key: string;\n hash: string;\n snippet: string;\n path: string;\n startLine: number;\n endLine: number;\n score: number;\n recallCount: number;\n avgScore: number;\n }> = [];\n\n const skipped: DreamingDeepPhaseSkipped = emptyDeepPhaseSkipped();\n for (const candidate of ranked) {\n if (existingMarkers.keys.has(candidate.key)) {\n skipped.alreadyPromotedKey += 1;\n // Treat as already applied; mark promotedAt for idempotency and keep going.\n const entry = store.entries[candidate.key];\n if (entry && !entry.promotedAt) {\n entry.promotedAt = now.toISOString();\n }\n continue;\n }\n const rehydrated = await rehydrateSnippet({ workspaceDir: params.workspaceDir, candidate });\n if (!rehydrated) {\n skipped.rehydrateFailed += 1;\n continue;\n }\n if (isContaminatedSnippet(rehydrated.snippet)) {\n skipped.contaminated += 1;\n continue;\n }\n const hash = snippetHash(rehydrated.snippet);\n if (existingMarkers.hashes.has(hash)) {\n skipped.hashDuplicate += 1;\n // Already promoted (possibly from a different key/line range). Mark promoted for idempotency.\n const entry = store.entries[candidate.key];\n if (entry && !entry.promotedAt) {\n entry.promotedAt = now.toISOString();\n }\n continue;\n }\n appliedCandidates.push({\n key: candidate.key,\n hash,\n snippet: rehydrated.snippet,\n path: candidate.path,\n startLine: rehydrated.startLine,\n endLine: rehydrated.endLine,\n score: candidate.score,\n recallCount: candidate.recallCount,\n avgScore: candidate.avgScore,\n });\n }\n\n if (appliedCandidates.length === 0) {\n await saveDreamingStore({ workspaceDir: params.workspaceDir, store });\n return {\n ok: true,\n reason: 'candidates were stale or already applied',\n candidates: ranked.length,\n applied: 0,\n memoryPath,\n skipped,\n };\n }\n\n const day = isoDay(now);\n const header = existing.trim().length > 0 ? '' : '# Long-Term Memory\\n\\n';\n const sectionLines: string[] = ['', `## Promoted From Short-Term Memory (${day})`, ''];\n for (const c of appliedCandidates) {\n const src = `${c.path}:${c.startLine}-${c.endLine}`;\n sectionLines.push(markerForPromotion(c.key, c.hash));\n sectionLines.push(\n `- ${c.snippet} [score=${c.score.toFixed(3)} recalls=${c.recallCount} avg=${c.avgScore.toFixed(3)} source=${src}]`,\n );\n }\n sectionLines.push('');\n\n const next = `${header}${existing.endsWith('\\n') || existing.length === 0 ? existing : `${existing}\\n`}${sectionLines.join('\\n')}`;\n await fs.writeFile(memoryPath, next, 'utf-8');\n\n const nowIso = now.toISOString();\n for (const c of appliedCandidates) {\n const entry = store.entries[c.key];\n if (entry) {\n entry.promotedAt = nowIso;\n entry.snippet = c.snippet;\n entry.startLine = c.startLine;\n entry.endLine = c.endLine;\n }\n }\n store.updatedAt = nowIso;\n await saveDreamingStore({ workspaceDir: params.workspaceDir, store });\n\n log.info(\n { workspaceDir: params.workspaceDir, candidates: ranked.length, applied: appliedCandidates.length },\n 'Dreaming deep promotion complete',\n );\n\n return {\n ok: true,\n reason: 'applied promotions',\n candidates: ranked.length,\n applied: appliedCandidates.length,\n memoryPath,\n skipped,\n };\n });\n\n const finishedAt = new Date().toISOString();\n const empty = emptyDeepPhaseSkipped();\n const resultSkipped = 'skipped' in result ? result.skipped : empty;\n await writeDreamingDeepLastRun({\n workspaceDir: params.workspaceDir,\n lastRun: buildDeepLastRun({\n runId,\n startedAt,\n finishedAt,\n t0,\n ok: result.ok,\n reason: result.reason,\n config: cfg,\n memoryPath: result.memoryPath,\n deep: {\n candidatesRanked: result.candidates,\n applied: result.applied,\n skipped: resultSkipped,\n },\n }),\n }).catch(() => undefined);\n\n return {\n ok: result.ok,\n reason: result.reason,\n candidates: result.candidates,\n applied: result.applied,\n memoryPath: result.memoryPath,\n };\n } catch (err) {\n const finishedAt = new Date().toISOString();\n const em = err instanceof Error ? err.message : String(err);\n const z = emptyDeepPhaseSkipped();\n await writeDreamingDeepLastRun({\n workspaceDir: params.workspaceDir,\n lastRun: buildDeepLastRun({\n runId,\n startedAt,\n finishedAt,\n t0,\n ok: false,\n reason: 'error',\n config: cfg,\n memoryPath,\n errorMessage: em,\n deep: { candidatesRanked: 0, applied: 0, skipped: z },\n }),\n }).catch(() => undefined);\n throw err;\n }\n}\n\n"],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type DreamingPhaseId } from './constants.js';
|
|
2
|
+
export type DreamingEventBase = {
|
|
3
|
+
timestamp: string;
|
|
4
|
+
phase: DreamingPhaseId;
|
|
5
|
+
ok: boolean;
|
|
6
|
+
reason: string;
|
|
7
|
+
durationMs: number;
|
|
8
|
+
};
|
|
9
|
+
export type DreamingLightEvent = DreamingEventBase & {
|
|
10
|
+
phase: 'light';
|
|
11
|
+
scannedEntries: number;
|
|
12
|
+
newSignals: number;
|
|
13
|
+
deduped: number;
|
|
14
|
+
};
|
|
15
|
+
export type DreamingDeepEvent = DreamingEventBase & {
|
|
16
|
+
phase: 'deep';
|
|
17
|
+
candidates: number;
|
|
18
|
+
applied: number;
|
|
19
|
+
};
|
|
20
|
+
export type DreamingRemEvent = DreamingEventBase & {
|
|
21
|
+
phase: 'rem';
|
|
22
|
+
patternsDiscovered: number;
|
|
23
|
+
entriesAnalyzed: number;
|
|
24
|
+
};
|
|
25
|
+
export type DreamingEvent = DreamingLightEvent | DreamingDeepEvent | DreamingRemEvent;
|
|
26
|
+
/**
|
|
27
|
+
* Append a single event line to `memory/.dreams/events.jsonl`.
|
|
28
|
+
* Creates the directory and file if they don't exist.
|
|
29
|
+
* Failures are silently ignored so audit logging never blocks execution.
|
|
30
|
+
*/
|
|
31
|
+
export declare function appendDreamingEvent(workspaceDir: string, event: DreamingEvent): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Read the most recent N events from the events log.
|
|
34
|
+
* Returns newest-first. If the file doesn't exist, returns an empty array.
|
|
35
|
+
*/
|
|
36
|
+
export declare function readDreamingEvents(workspaceDir: string, limit?: number): Promise<DreamingEvent[]>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { DREAMING_DIR_RELATIVE, DREAMING_EVENTS_LOG_RELATIVE } from "./constants.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
//#region src/agent/memory/dreaming/events.ts
|
|
5
|
+
/**
|
|
6
|
+
* Append a single event line to `memory/.dreams/events.jsonl`.
|
|
7
|
+
* Creates the directory and file if they don't exist.
|
|
8
|
+
* Failures are silently ignored so audit logging never blocks execution.
|
|
9
|
+
*/
|
|
10
|
+
async function appendDreamingEvent(workspaceDir, event) {
|
|
11
|
+
try {
|
|
12
|
+
const dirPath = path.join(workspaceDir, DREAMING_DIR_RELATIVE);
|
|
13
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
14
|
+
const filePath = path.join(workspaceDir, DREAMING_EVENTS_LOG_RELATIVE);
|
|
15
|
+
const line = JSON.stringify(event) + "\n";
|
|
16
|
+
await fs.appendFile(filePath, line, "utf-8");
|
|
17
|
+
} catch {}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Read the most recent N events from the events log.
|
|
21
|
+
* Returns newest-first. If the file doesn't exist, returns an empty array.
|
|
22
|
+
*/
|
|
23
|
+
async function readDreamingEvents(workspaceDir, limit = 50) {
|
|
24
|
+
const filePath = path.join(workspaceDir, DREAMING_EVENTS_LOG_RELATIVE);
|
|
25
|
+
let raw;
|
|
26
|
+
try {
|
|
27
|
+
raw = await fs.readFile(filePath, "utf-8");
|
|
28
|
+
} catch (err) {
|
|
29
|
+
if (err?.code === "ENOENT") return [];
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
const tail = raw.split("\n").map((line) => line.trim()).filter(Boolean).slice(-Math.abs(limit));
|
|
33
|
+
const events = [];
|
|
34
|
+
for (const line of tail) try {
|
|
35
|
+
const parsed = JSON.parse(line);
|
|
36
|
+
if (parsed && typeof parsed === "object" && parsed.timestamp && parsed.phase) events.push(parsed);
|
|
37
|
+
} catch {}
|
|
38
|
+
events.reverse();
|
|
39
|
+
return events;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { appendDreamingEvent, readDreamingEvents };
|
|
43
|
+
|
|
44
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","names":[],"sources":["../../../../../src/agent/memory/dreaming/events.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport { DREAMING_DIR_RELATIVE, DREAMING_EVENTS_LOG_RELATIVE, type DreamingPhaseId } from './constants.js';\n\n// ── Event types ────────────────────────────────────────────────────────\n\nexport type DreamingEventBase = {\n timestamp: string;\n phase: DreamingPhaseId;\n ok: boolean;\n reason: string;\n durationMs: number;\n};\n\nexport type DreamingLightEvent = DreamingEventBase & {\n phase: 'light';\n scannedEntries: number;\n newSignals: number;\n deduped: number;\n};\n\nexport type DreamingDeepEvent = DreamingEventBase & {\n phase: 'deep';\n candidates: number;\n applied: number;\n};\n\nexport type DreamingRemEvent = DreamingEventBase & {\n phase: 'rem';\n patternsDiscovered: number;\n entriesAnalyzed: number;\n};\n\nexport type DreamingEvent = DreamingLightEvent | DreamingDeepEvent | DreamingRemEvent;\n\n// ── Write ──────────────────────────────────────────────────────────────\n\n/**\n * Append a single event line to `memory/.dreams/events.jsonl`.\n * Creates the directory and file if they don't exist.\n * Failures are silently ignored so audit logging never blocks execution.\n */\nexport async function appendDreamingEvent(workspaceDir: string, event: DreamingEvent): Promise<void> {\n try {\n const dirPath = path.join(workspaceDir, DREAMING_DIR_RELATIVE);\n await fs.mkdir(dirPath, { recursive: true });\n const filePath = path.join(workspaceDir, DREAMING_EVENTS_LOG_RELATIVE);\n const line = JSON.stringify(event) + '\\n';\n await fs.appendFile(filePath, line, 'utf-8');\n } catch {\n // Audit logging must not block or throw.\n }\n}\n\n// ── Read ───────────────────────────────────────────────────────────────\n\n/**\n * Read the most recent N events from the events log.\n * Returns newest-first. If the file doesn't exist, returns an empty array.\n */\nexport async function readDreamingEvents(\n workspaceDir: string,\n limit = 50,\n): Promise<DreamingEvent[]> {\n const filePath = path.join(workspaceDir, DREAMING_EVENTS_LOG_RELATIVE);\n let raw: string;\n try {\n raw = await fs.readFile(filePath, 'utf-8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n if (code === 'ENOENT') return [];\n throw err;\n }\n\n const lines = raw\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean);\n\n // Take the last `limit` lines (newest entries are at the end).\n const tail = lines.slice(-Math.abs(limit));\n\n const events: DreamingEvent[] = [];\n for (const line of tail) {\n try {\n const parsed = JSON.parse(line) as DreamingEvent;\n if (parsed && typeof parsed === 'object' && parsed.timestamp && parsed.phase) {\n events.push(parsed);\n }\n } catch {\n // Skip malformed lines.\n }\n }\n\n // Return newest first.\n events.reverse();\n return events;\n}\n"],"mappings":";;;;;;;;;AA2CA,eAAsB,oBAAoB,cAAsB,OAAqC;AACnG,KAAI;EACF,MAAM,UAAU,KAAK,KAAK,cAAc,sBAAsB;AAC9D,QAAM,GAAG,MAAM,SAAS,EAAE,WAAW,MAAM,CAAC;EAC5C,MAAM,WAAW,KAAK,KAAK,cAAc,6BAA6B;EACtE,MAAM,OAAO,KAAK,UAAU,MAAM,GAAG;AACrC,QAAM,GAAG,WAAW,UAAU,MAAM,QAAQ;SACtC;;;;;;AAWV,eAAsB,mBACpB,cACA,QAAQ,IACkB;CAC1B,MAAM,WAAW,KAAK,KAAK,cAAc,6BAA6B;CACtE,IAAI;AACJ,KAAI;AACF,QAAM,MAAM,GAAG,SAAS,UAAU,QAAQ;UACnC,KAAK;AAEZ,MADc,KAA2C,SAC5C,SAAU,QAAO,EAAE;AAChC,QAAM;;CASR,MAAM,OANQ,IACX,MAAM,KAAK,CACX,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,OAAO,QAGQ,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC;CAE1C,MAAM,SAA0B,EAAE;AAClC,MAAK,MAAM,QAAQ,KACjB,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,MAAI,UAAU,OAAO,WAAW,YAAY,OAAO,aAAa,OAAO,MACrE,QAAO,KAAK,OAAO;SAEf;AAMV,QAAO,SAAS;AAChB,QAAO"}
|