odai-dsh-agent 0.2.3 → 0.2.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/README.md +3 -3
- package/build/bin/odai-dsh-agent.d.mts +3 -0
- package/build/bin/odai-dsh-agent.d.mts.map +1 -0
- package/build/bin/odai-dsh-agent.mjs +114 -0
- package/build/bin/odai-dsh-agent.mjs.map +1 -0
- package/build/src/dsh-version.d.mts +16 -0
- package/build/src/dsh-version.d.mts.map +1 -0
- package/build/src/dsh-version.mjs +20 -0
- package/build/src/dsh-version.mjs.map +1 -0
- package/build/src/installer.d.mts +46 -0
- package/build/src/installer.d.mts.map +1 -0
- package/build/src/installer.mjs +397 -0
- package/build/src/installer.mjs.map +1 -0
- package/package.json +13 -12
- package/preset/odai/runtime/compaction-config.d.mts +66 -0
- package/preset/odai/runtime/compaction-config.d.mts.map +1 -0
- package/preset/odai/runtime/compaction-config.mjs +320 -342
- package/preset/odai/runtime/compaction-config.mjs.map +1 -0
- package/preset/odai/runtime/compaction-runtime.d.mts +68 -0
- package/preset/odai/runtime/compaction-runtime.d.mts.map +1 -0
- package/preset/odai/runtime/compaction-runtime.mjs +157 -0
- package/preset/odai/runtime/compaction-runtime.mjs.map +1 -0
- package/preset/odai/runtime/context-activation.d.mts +31 -0
- package/preset/odai/runtime/context-activation.d.mts.map +1 -0
- package/preset/odai/runtime/context-activation.mjs +55 -49
- package/preset/odai/runtime/context-activation.mjs.map +1 -0
- package/preset/odai/runtime/context-capability.d.mts +16 -0
- package/preset/odai/runtime/context-capability.d.mts.map +1 -0
- package/preset/odai/runtime/context-capability.mjs +79 -74
- package/preset/odai/runtime/context-capability.mjs.map +1 -0
- package/preset/odai/runtime/governance.d.mts +30 -0
- package/preset/odai/runtime/governance.d.mts.map +1 -0
- package/preset/odai/runtime/governance.mjs +126 -113
- package/preset/odai/runtime/governance.mjs.map +1 -0
- package/preset/odai/runtime/human-care.d.mts +13 -0
- package/preset/odai/runtime/human-care.d.mts.map +1 -0
- package/preset/odai/runtime/human-care.mjs +45 -42
- package/preset/odai/runtime/human-care.mjs.map +1 -0
- package/preset/odai/runtime/human-safety-continuity-store.d.mts +43 -0
- package/preset/odai/runtime/human-safety-continuity-store.d.mts.map +1 -0
- package/preset/odai/runtime/human-safety-continuity-store.mjs +193 -215
- package/preset/odai/runtime/human-safety-continuity-store.mjs.map +1 -0
- package/preset/odai/runtime/human-safety-continuity.d.mts +27 -0
- package/preset/odai/runtime/human-safety-continuity.d.mts.map +1 -0
- package/preset/odai/runtime/human-safety-continuity.mjs +205 -216
- package/preset/odai/runtime/human-safety-continuity.mjs.map +1 -0
- package/preset/odai/runtime/human-safety.d.mts +14 -0
- package/preset/odai/runtime/human-safety.d.mts.map +1 -0
- package/preset/odai/runtime/human-safety.mjs +50 -47
- package/preset/odai/runtime/human-safety.mjs.map +1 -0
- package/preset/odai/runtime/index.d.mts +8 -0
- package/preset/odai/runtime/index.d.mts.map +1 -0
- package/preset/odai/runtime/index.mjs +161 -2441
- package/preset/odai/runtime/index.mjs.map +1 -0
- package/preset/odai/runtime/lifecycle-runtime.d.mts +83 -0
- package/preset/odai/runtime/lifecycle-runtime.d.mts.map +1 -0
- package/preset/odai/runtime/lifecycle-runtime.mjs +1081 -0
- package/preset/odai/runtime/lifecycle-runtime.mjs.map +1 -0
- package/preset/odai/runtime/model-route.d.mts +22 -0
- package/preset/odai/runtime/model-route.d.mts.map +1 -0
- package/preset/odai/runtime/model-route.mjs +68 -60
- package/preset/odai/runtime/model-route.mjs.map +1 -0
- package/preset/odai/runtime/output-config.d.mts +54 -0
- package/preset/odai/runtime/output-config.d.mts.map +1 -0
- package/preset/odai/runtime/output-config.mjs +289 -315
- package/preset/odai/runtime/output-config.mjs.map +1 -0
- package/preset/odai/runtime/output-policy-state.d.mts +3 -0
- package/preset/odai/runtime/output-policy-state.d.mts.map +1 -0
- package/preset/odai/runtime/output-policy-state.mjs +41 -29
- package/preset/odai/runtime/output-policy-state.mjs.map +1 -0
- package/preset/odai/runtime/prompt-runtime.d.mts +55 -0
- package/preset/odai/runtime/prompt-runtime.d.mts.map +1 -0
- package/preset/odai/runtime/prompt-runtime.mjs +303 -0
- package/preset/odai/runtime/prompt-runtime.mjs.map +1 -0
- package/preset/odai/runtime/research-packet.d.mts +30 -0
- package/preset/odai/runtime/research-packet.d.mts.map +1 -0
- package/preset/odai/runtime/research-packet.mjs +116 -117
- package/preset/odai/runtime/research-packet.mjs.map +1 -0
- package/preset/odai/runtime/responsibility-gap.d.mts +26 -0
- package/preset/odai/runtime/responsibility-gap.d.mts.map +1 -0
- package/preset/odai/runtime/responsibility-gap.mjs +91 -85
- package/preset/odai/runtime/responsibility-gap.mjs.map +1 -0
- package/preset/odai/runtime/responsibility-scope.d.mts +69 -0
- package/preset/odai/runtime/responsibility-scope.d.mts.map +1 -0
- package/preset/odai/runtime/responsibility-scope.mjs +199 -171
- package/preset/odai/runtime/responsibility-scope.mjs.map +1 -0
- package/preset/odai/runtime/role-overlays.d.mts +5 -0
- package/preset/odai/runtime/role-overlays.d.mts.map +1 -0
- package/preset/odai/runtime/role-overlays.mjs +14 -13
- package/preset/odai/runtime/role-overlays.mjs.map +1 -0
- package/preset/odai/runtime/route-card.d.mts +42 -0
- package/preset/odai/runtime/route-card.d.mts.map +1 -0
- package/preset/odai/runtime/route-card.mjs +158 -146
- package/preset/odai/runtime/route-card.mjs.map +1 -0
- package/preset/odai/runtime/router.d.mts +79 -0
- package/preset/odai/runtime/router.d.mts.map +1 -0
- package/preset/odai/runtime/router.mjs +491 -559
- package/preset/odai/runtime/router.mjs.map +1 -0
- package/preset/odai/runtime/routing-config.d.mts +76 -0
- package/preset/odai/runtime/routing-config.d.mts.map +1 -0
- package/preset/odai/runtime/routing-config.mjs +373 -438
- package/preset/odai/runtime/routing-config.mjs.map +1 -0
- package/preset/odai/runtime/routing-context.d.mts +47 -0
- package/preset/odai/runtime/routing-context.d.mts.map +1 -0
- package/preset/odai/runtime/routing-context.mjs +238 -273
- package/preset/odai/runtime/routing-context.mjs.map +1 -0
- package/preset/odai/runtime/runtime-config.d.mts +24 -0
- package/preset/odai/runtime/runtime-config.d.mts.map +1 -0
- package/preset/odai/runtime/runtime-config.mjs +181 -0
- package/preset/odai/runtime/runtime-config.mjs.map +1 -0
- package/preset/odai/runtime/runtime-support.d.mts +91 -0
- package/preset/odai/runtime/runtime-support.d.mts.map +1 -0
- package/preset/odai/runtime/runtime-support.mjs +371 -0
- package/preset/odai/runtime/runtime-support.mjs.map +1 -0
- package/preset/odai/runtime/runtime-types.d.mts +235 -0
- package/preset/odai/runtime/runtime-types.d.mts.map +1 -0
- package/preset/odai/runtime/runtime-types.mjs +4 -0
- package/preset/odai/runtime/runtime-types.mjs.map +1 -0
- package/preset/odai/runtime/semantic-memory-store.d.mts +110 -0
- package/preset/odai/runtime/semantic-memory-store.d.mts.map +1 -0
- package/preset/odai/runtime/semantic-memory-store.mjs +271 -385
- package/preset/odai/runtime/semantic-memory-store.mjs.map +1 -0
- package/preset/odai/runtime/semantic-memory.d.mts +88 -0
- package/preset/odai/runtime/semantic-memory.d.mts.map +1 -0
- package/preset/odai/runtime/semantic-memory.mjs +790 -750
- package/preset/odai/runtime/semantic-memory.mjs.map +1 -0
- package/preset/odai/runtime/session-compat.d.mts +31 -0
- package/preset/odai/runtime/session-compat.d.mts.map +1 -0
- package/preset/odai/runtime/session-compat.mjs +301 -328
- package/preset/odai/runtime/session-compat.mjs.map +1 -0
- package/preset/odai/runtime/session-evidence.d.mts +25 -0
- package/preset/odai/runtime/session-evidence.d.mts.map +1 -0
- package/preset/odai/runtime/session-evidence.mjs +309 -287
- package/preset/odai/runtime/session-evidence.mjs.map +1 -0
- package/preset/odai/runtime/skill-bundle.d.mts +53 -0
- package/preset/odai/runtime/skill-bundle.d.mts.map +1 -0
- package/preset/odai/runtime/skill-bundle.mjs +286 -276
- package/preset/odai/runtime/skill-bundle.mjs.map +1 -0
- package/preset/odai/runtime/skill-evolution.d.mts +112 -0
- package/preset/odai/runtime/skill-evolution.d.mts.map +1 -0
- package/preset/odai/runtime/skill-evolution.mjs +1287 -1261
- package/preset/odai/runtime/skill-evolution.mjs.map +1 -0
- package/preset/odai/runtime/skill-selection-state.d.mts +5 -0
- package/preset/odai/runtime/skill-selection-state.d.mts.map +1 -0
- package/preset/odai/runtime/skill-selection-state.mjs +59 -43
- package/preset/odai/runtime/skill-selection-state.mjs.map +1 -0
- package/preset/odai/runtime/skill-selector.d.mts +28 -0
- package/preset/odai/runtime/skill-selector.d.mts.map +1 -0
- package/preset/odai/runtime/skill-selector.mjs +100 -109
- package/preset/odai/runtime/skill-selector.mjs.map +1 -0
- package/preset/odai/runtime/skill-source-config.d.mts +32 -0
- package/preset/odai/runtime/skill-source-config.d.mts.map +1 -0
- package/preset/odai/runtime/skill-source-config.mjs +200 -210
- package/preset/odai/runtime/skill-source-config.mjs.map +1 -0
- package/preset/odai/runtime/store-lock.d.mts +2 -0
- package/preset/odai/runtime/store-lock.d.mts.map +1 -0
- package/preset/odai/runtime/store-lock.mjs +92 -87
- package/preset/odai/runtime/store-lock.mjs.map +1 -0
- package/preset/odai/runtime/tool-runtime.d.mts +43 -0
- package/preset/odai/runtime/tool-runtime.d.mts.map +1 -0
- package/preset/odai/runtime/tool-runtime.mjs +221 -0
- package/preset/odai/runtime/tool-runtime.mjs.map +1 -0
- package/bin/odai-dsh-agent.mjs +0 -108
- package/scripts/verify-agent-load.mjs +0 -257
- package/src/dsh-version.mjs +0 -24
- package/src/installer.mjs +0 -398
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
closeSync,
|
|
4
|
-
constants,
|
|
5
|
-
existsSync,
|
|
6
|
-
fstatSync,
|
|
7
|
-
fsyncSync,
|
|
8
|
-
lstatSync,
|
|
9
|
-
mkdirSync,
|
|
10
|
-
openSync,
|
|
11
|
-
readFileSync,
|
|
12
|
-
realpathSync,
|
|
13
|
-
renameSync,
|
|
14
|
-
rmSync,
|
|
15
|
-
writeFileSync,
|
|
16
|
-
} from "node:fs";
|
|
2
|
+
import { closeSync, constants, existsSync, fstatSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
17
3
|
import { homedir } from "node:os";
|
|
18
4
|
import { basename, dirname, resolve } from "node:path";
|
|
19
|
-
|
|
20
5
|
import { acquireOwnedStoreLock } from "./store-lock.mjs";
|
|
21
|
-
|
|
6
|
+
import { isUnknownRecord } from "./runtime-types.mjs";
|
|
22
7
|
export const MEMORY_STORE_SCHEMA_VERSION = 1;
|
|
23
8
|
export const MEMORY_EXTRACTOR_VERSION = 1;
|
|
24
9
|
export const MEMORY_MODES = Object.freeze(["auto", "off"]);
|
|
@@ -28,425 +13,326 @@ export const DEFAULT_MEMORY_SETTINGS = Object.freeze({ mode: "auto" });
|
|
|
28
13
|
export const MAX_MEMORY_ENTRIES = 1_000;
|
|
29
14
|
export const MAX_MEMORY_PROVENANCE = 8;
|
|
30
15
|
export const MAX_MEMORY_VALUE_CHARS = 600;
|
|
31
|
-
|
|
32
16
|
const STORE_FIELDS = new Set(["schemaVersion", "settings", "entries"]);
|
|
33
17
|
const SETTINGS_FIELDS = new Set(["mode"]);
|
|
34
18
|
const ENTRY_FIELDS = new Set([
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
"category",
|
|
38
|
-
"subject",
|
|
39
|
-
"value",
|
|
40
|
-
"status",
|
|
41
|
-
"confidence",
|
|
42
|
-
"supersedes",
|
|
43
|
-
"conflictsWith",
|
|
44
|
-
"provenance",
|
|
45
|
-
"createdAt",
|
|
46
|
-
"updatedAt",
|
|
47
|
-
"occurrences",
|
|
19
|
+
"id", "scope", "category", "subject", "value", "status", "confidence", "supersedes", "conflictsWith",
|
|
20
|
+
"provenance", "createdAt", "updatedAt", "occurrences",
|
|
48
21
|
]);
|
|
49
22
|
const SCOPE_FIELDS = new Set(["kind", "key", "label"]);
|
|
50
23
|
const PROVENANCE_FIELDS = new Set([
|
|
51
|
-
|
|
52
|
-
"sessionHash",
|
|
53
|
-
"messageHash",
|
|
54
|
-
"turn",
|
|
55
|
-
"eventSeq",
|
|
56
|
-
"excerptSha256",
|
|
57
|
-
"observedAt",
|
|
58
|
-
"extraction",
|
|
59
|
-
"extractorVersion",
|
|
24
|
+
"sourceKind", "sessionHash", "messageHash", "turn", "eventSeq", "excerptSha256", "observedAt", "extraction", "extractorVersion",
|
|
60
25
|
]);
|
|
61
|
-
|
|
62
|
-
export class MemoryStoreValidationError extends Error {}
|
|
63
|
-
|
|
64
|
-
function hash(value) {
|
|
65
|
-
return createHash("sha256").update(value).digest("hex");
|
|
26
|
+
export class MemoryStoreValidationError extends Error {
|
|
66
27
|
}
|
|
67
|
-
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return value;
|
|
28
|
+
function hash(value) { return createHash("sha256").update(value).digest("hex"); }
|
|
29
|
+
function errorCode(error) {
|
|
30
|
+
if (error === null || typeof error !== "object" || !("code" in error))
|
|
31
|
+
return undefined;
|
|
32
|
+
return typeof error.code === "string" ? error.code : undefined;
|
|
73
33
|
}
|
|
74
|
-
|
|
75
34
|
function rejectUnknown(value, allowed, field) {
|
|
76
|
-
|
|
77
|
-
|
|
35
|
+
const unknownFields = Object.keys(value).filter((name) => !allowed.has(name));
|
|
36
|
+
if (unknownFields.length > 0)
|
|
37
|
+
throw new TypeError(`${field} has unknown fields: ${unknownFields.join(", ")}`);
|
|
78
38
|
}
|
|
79
|
-
|
|
80
39
|
function requiredString(value, field, max = 1_000) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
40
|
+
if (typeof value !== "string" || value.length === 0 || value.length > max) {
|
|
41
|
+
throw new TypeError(`${field} must be a non-empty string of at most ${max} characters`);
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
85
44
|
}
|
|
86
|
-
|
|
87
45
|
function safeInteger(value, field) {
|
|
88
|
-
|
|
89
|
-
|
|
46
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
|
|
47
|
+
throw new TypeError(`${field} must be a non-negative integer`);
|
|
48
|
+
return value;
|
|
90
49
|
}
|
|
91
|
-
|
|
50
|
+
function isMemoryMode(value) { return typeof value === "string" && MEMORY_MODES.includes(value); }
|
|
51
|
+
function isMemoryCategory(value) { return typeof value === "string" && MEMORY_CATEGORIES.includes(value); }
|
|
52
|
+
function isMemoryStatus(value) { return typeof value === "string" && MEMORY_STATUSES.includes(value); }
|
|
92
53
|
function validateMode(mode, field = "memory mode") {
|
|
93
|
-
|
|
94
|
-
|
|
54
|
+
if (!isMemoryMode(mode))
|
|
55
|
+
throw new TypeError(`${field} must be auto or off`);
|
|
56
|
+
return mode;
|
|
95
57
|
}
|
|
96
|
-
|
|
97
58
|
function validateScope(value, field) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
...(scope.label === undefined ? {} : { label: scope.label }),
|
|
111
|
-
});
|
|
59
|
+
if (!isUnknownRecord(value))
|
|
60
|
+
throw new TypeError(`${field} must be an object`);
|
|
61
|
+
rejectUnknown(value, SCOPE_FIELDS, field);
|
|
62
|
+
if (value.kind !== "global" && value.kind !== "project")
|
|
63
|
+
throw new TypeError(`${field}.kind must be global or project`);
|
|
64
|
+
const key = requiredString(value.key, `${field}.key`, 64);
|
|
65
|
+
if (value.kind === "global" && key !== "global")
|
|
66
|
+
throw new TypeError(`${field}.key must be global for global scope`);
|
|
67
|
+
if (value.kind === "project" && !/^[a-f0-9]{64}$/u.test(key))
|
|
68
|
+
throw new TypeError(`${field}.key must be a sha256 project key`);
|
|
69
|
+
const label = value.label === undefined ? undefined : requiredString(value.label, `${field}.label`, 120);
|
|
70
|
+
return Object.freeze({ kind: value.kind, key, ...(label === undefined ? {} : { label }) });
|
|
112
71
|
}
|
|
113
|
-
|
|
114
72
|
function validateProvenance(value, field) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
});
|
|
73
|
+
if (!isUnknownRecord(value))
|
|
74
|
+
throw new TypeError(`${field} must be an object`);
|
|
75
|
+
rejectUnknown(value, PROVENANCE_FIELDS, field);
|
|
76
|
+
if (value.sourceKind !== "direct-user")
|
|
77
|
+
throw new TypeError(`${field}.sourceKind must be direct-user`);
|
|
78
|
+
const sessionHash = requiredString(value.sessionHash, `${field}.sessionHash`, 64);
|
|
79
|
+
const messageHash = requiredString(value.messageHash, `${field}.messageHash`, 64);
|
|
80
|
+
const excerptSha256 = requiredString(value.excerptSha256, `${field}.excerptSha256`, 64);
|
|
81
|
+
if (!/^[a-f0-9]{64}$/u.test(sessionHash))
|
|
82
|
+
throw new TypeError(`${field}.sessionHash must be sha256`);
|
|
83
|
+
if (!/^[a-f0-9]{64}$/u.test(messageHash))
|
|
84
|
+
throw new TypeError(`${field}.messageHash must be sha256`);
|
|
85
|
+
if (!/^[a-f0-9]{64}$/u.test(excerptSha256))
|
|
86
|
+
throw new TypeError(`${field}.excerptSha256 must be sha256`);
|
|
87
|
+
const turn = safeInteger(value.turn, `${field}.turn`);
|
|
88
|
+
const eventSeq = value.eventSeq === undefined ? undefined : safeInteger(value.eventSeq, `${field}.eventSeq`);
|
|
89
|
+
const observedAt = safeInteger(value.observedAt, `${field}.observedAt`);
|
|
90
|
+
if (value.extraction !== "local-explicit" && value.extraction !== "tool-exact-excerpt")
|
|
91
|
+
throw new TypeError(`${field}.extraction is unsupported`);
|
|
92
|
+
if (value.extractorVersion !== MEMORY_EXTRACTOR_VERSION)
|
|
93
|
+
throw new TypeError(`${field}.extractorVersion is unsupported`);
|
|
94
|
+
return Object.freeze({
|
|
95
|
+
sourceKind: "direct-user", sessionHash, messageHash, turn, ...(eventSeq === undefined ? {} : { eventSeq }),
|
|
96
|
+
excerptSha256, observedAt, extraction: value.extraction, extractorVersion: MEMORY_EXTRACTOR_VERSION,
|
|
97
|
+
});
|
|
141
98
|
}
|
|
142
|
-
|
|
143
99
|
function validateEntry(value, field) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
||
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
scope,
|
|
175
|
-
|
|
176
|
-
subject: entry.subject,
|
|
177
|
-
value: entry.value,
|
|
178
|
-
status: entry.status,
|
|
179
|
-
confidence: entry.confidence,
|
|
180
|
-
supersedes: Object.freeze(supersedes),
|
|
181
|
-
conflictsWith: Object.freeze(conflictsWith),
|
|
182
|
-
provenance: Object.freeze(provenance),
|
|
183
|
-
createdAt,
|
|
184
|
-
updatedAt,
|
|
185
|
-
occurrences,
|
|
186
|
-
});
|
|
100
|
+
if (!isUnknownRecord(value))
|
|
101
|
+
throw new TypeError(`${field} must be an object`);
|
|
102
|
+
rejectUnknown(value, ENTRY_FIELDS, field);
|
|
103
|
+
const id = requiredString(value.id, `${field}.id`, 80);
|
|
104
|
+
const scope = validateScope(value.scope, `${field}.scope`);
|
|
105
|
+
if (!isMemoryCategory(value.category))
|
|
106
|
+
throw new TypeError(`${field}.category is unsupported`);
|
|
107
|
+
const subject = requiredString(value.subject, `${field}.subject`, 64);
|
|
108
|
+
const entryValue = requiredString(value.value, `${field}.value`, MAX_MEMORY_VALUE_CHARS);
|
|
109
|
+
if (!isMemoryStatus(value.status))
|
|
110
|
+
throw new TypeError(`${field}.status is unsupported`);
|
|
111
|
+
if (value.confidence !== "high" && value.confidence !== "medium")
|
|
112
|
+
throw new TypeError(`${field}.confidence is unsupported`);
|
|
113
|
+
if (!Array.isArray(value.supersedes) || value.supersedes.length > 64)
|
|
114
|
+
throw new TypeError(`${field}.supersedes must be an array with at most 64 entries`);
|
|
115
|
+
const supersedes = value.supersedes.map((entryId, index) => requiredString(entryId, `${field}.supersedes[${index}]`, 80));
|
|
116
|
+
if (!Array.isArray(value.conflictsWith) || value.conflictsWith.length > 64)
|
|
117
|
+
throw new TypeError(`${field}.conflictsWith must be an array with at most 64 entries`);
|
|
118
|
+
const conflictsWith = value.conflictsWith.map((entryId, index) => requiredString(entryId, `${field}.conflictsWith[${index}]`, 80));
|
|
119
|
+
if (!Array.isArray(value.provenance) || value.provenance.length === 0 || value.provenance.length > MAX_MEMORY_PROVENANCE) {
|
|
120
|
+
throw new TypeError(`${field}.provenance must contain 1-${MAX_MEMORY_PROVENANCE} entries`);
|
|
121
|
+
}
|
|
122
|
+
const provenance = value.provenance.map((item, index) => validateProvenance(item, `${field}.provenance[${index}]`));
|
|
123
|
+
const createdAt = safeInteger(value.createdAt, `${field}.createdAt`);
|
|
124
|
+
const updatedAt = safeInteger(value.updatedAt, `${field}.updatedAt`);
|
|
125
|
+
if (updatedAt < createdAt)
|
|
126
|
+
throw new TypeError(`${field}.updatedAt must not precede createdAt`);
|
|
127
|
+
const occurrences = safeInteger(value.occurrences, `${field}.occurrences`);
|
|
128
|
+
if (occurrences < 1)
|
|
129
|
+
throw new TypeError(`${field}.occurrences must be positive`);
|
|
130
|
+
return Object.freeze({ id, scope, category: value.category, subject, value: entryValue, status: value.status, confidence: value.confidence,
|
|
131
|
+
supersedes: Object.freeze(supersedes), conflictsWith: Object.freeze(conflictsWith), provenance: Object.freeze(provenance), createdAt, updatedAt, occurrences });
|
|
187
132
|
}
|
|
188
|
-
|
|
189
133
|
function validateStore(value, field) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
schemaVersion: MEMORY_STORE_SCHEMA_VERSION,
|
|
211
|
-
settings,
|
|
212
|
-
entries: Object.freeze(entries),
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function emptyStore() {
|
|
217
|
-
return Object.freeze({
|
|
218
|
-
schemaVersion: MEMORY_STORE_SCHEMA_VERSION,
|
|
219
|
-
settings: Object.freeze({}),
|
|
220
|
-
entries: Object.freeze([]),
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function assertNoSymlink(path, label) {
|
|
225
|
-
if (!existsSync(path)) return;
|
|
226
|
-
const stat = lstatSync(path);
|
|
227
|
-
if (stat.isSymbolicLink()) throw new Error(`${label} must not be a symbolic link: ${path}`);
|
|
134
|
+
if (!isUnknownRecord(value))
|
|
135
|
+
throw new TypeError(`${field} must be an object`);
|
|
136
|
+
rejectUnknown(value, STORE_FIELDS, field);
|
|
137
|
+
if (value.schemaVersion !== MEMORY_STORE_SCHEMA_VERSION)
|
|
138
|
+
throw new TypeError(`${field} has unsupported schemaVersion ${String(value.schemaVersion)}`);
|
|
139
|
+
const settingsValue = value.settings === undefined ? {} : value.settings;
|
|
140
|
+
if (!isUnknownRecord(settingsValue))
|
|
141
|
+
throw new TypeError(`${field}.settings must be an object`);
|
|
142
|
+
rejectUnknown(settingsValue, SETTINGS_FIELDS, `${field}.settings`);
|
|
143
|
+
const settings = Object.freeze({ ...(settingsValue.mode === undefined ? {} : { mode: validateMode(settingsValue.mode, `${field}.settings.mode`) }) });
|
|
144
|
+
if (!Array.isArray(value.entries) || value.entries.length > MAX_MEMORY_ENTRIES)
|
|
145
|
+
throw new TypeError(`${field}.entries must be an array with at most ${MAX_MEMORY_ENTRIES} records`);
|
|
146
|
+
const entries = value.entries.map((entry, index) => validateEntry(entry, `${field}.entries[${index}]`));
|
|
147
|
+
const ids = new Set();
|
|
148
|
+
for (const entry of entries) {
|
|
149
|
+
if (ids.has(entry.id))
|
|
150
|
+
throw new TypeError(`${field}.entries contains duplicate id ${entry.id}`);
|
|
151
|
+
ids.add(entry.id);
|
|
152
|
+
}
|
|
153
|
+
return Object.freeze({ schemaVersion: MEMORY_STORE_SCHEMA_VERSION, settings, entries: Object.freeze(entries) });
|
|
228
154
|
}
|
|
229
|
-
|
|
155
|
+
function emptyStore() { return Object.freeze({ schemaVersion: MEMORY_STORE_SCHEMA_VERSION, settings: Object.freeze({}), entries: Object.freeze([]) }); }
|
|
156
|
+
function assertNoSymlink(path, label) { if (existsSync(path) && lstatSync(path).isSymbolicLink())
|
|
157
|
+
throw new Error(`${label} must not be a symbolic link: ${path}`); }
|
|
230
158
|
function assertSafeStorePath(storePath) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
return [grandparent, parent]
|
|
243
|
-
.filter((path) => existsSync(path))
|
|
244
|
-
.map((path) => {
|
|
245
|
-
const stat = lstatSync(path);
|
|
246
|
-
return Object.freeze({ path, dev: stat.dev, ino: stat.ino });
|
|
247
|
-
});
|
|
159
|
+
const parent = dirname(storePath);
|
|
160
|
+
const grandparent = dirname(parent);
|
|
161
|
+
assertNoSymlink(grandparent, "Odai memory parent");
|
|
162
|
+
assertNoSymlink(parent, "Odai memory directory");
|
|
163
|
+
assertNoSymlink(storePath, "Odai memory store");
|
|
164
|
+
if (existsSync(parent) && !lstatSync(parent).isDirectory())
|
|
165
|
+
throw new Error(`Odai memory directory is not a directory: ${parent}`);
|
|
166
|
+
if (existsSync(storePath) && !lstatSync(storePath).isFile())
|
|
167
|
+
throw new Error(`Odai memory store is not a regular file: ${storePath}`);
|
|
168
|
+
return [grandparent, parent].filter((path) => existsSync(path)).map((path) => { const stat = lstatSync(path); return Object.freeze({ path, dev: stat.dev, ino: stat.ino }); });
|
|
248
169
|
}
|
|
249
|
-
|
|
250
170
|
function assertDirectoryIdentities(identities) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
171
|
+
for (const identity of identities) {
|
|
172
|
+
const stat = lstatSync(identity.path);
|
|
173
|
+
if (stat.isSymbolicLink() || !stat.isDirectory() || stat.dev !== identity.dev || stat.ino !== identity.ino)
|
|
174
|
+
throw new Error(`Odai memory directory identity changed during an operation: ${identity.path}`);
|
|
255
175
|
}
|
|
256
|
-
}
|
|
257
176
|
}
|
|
258
|
-
|
|
259
177
|
function readRegularFileNoFollow(path) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
178
|
+
const noFollow = typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
|
|
179
|
+
let fd;
|
|
180
|
+
try {
|
|
181
|
+
fd = openSync(path, constants.O_RDONLY | noFollow);
|
|
182
|
+
const stat = fstatSync(fd);
|
|
183
|
+
if (!stat.isFile())
|
|
184
|
+
throw new Error(`Odai memory store is not a regular file: ${path}`);
|
|
185
|
+
return readFileSync(fd, "utf8");
|
|
186
|
+
}
|
|
187
|
+
finally {
|
|
188
|
+
if (fd !== undefined)
|
|
189
|
+
closeSync(fd);
|
|
190
|
+
}
|
|
270
191
|
}
|
|
271
|
-
|
|
272
192
|
export function resolveMemoryStorePath(configuredPath, env = process.env) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
193
|
+
if (configuredPath !== undefined) {
|
|
194
|
+
if (typeof configuredPath !== "string" || configuredPath.trim() === "")
|
|
195
|
+
throw new TypeError("config.memory.storePath must be a non-empty string");
|
|
196
|
+
return resolve(configuredPath.trim());
|
|
276
197
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
const dshHome = typeof env.DSH_HOME === "string" && env.DSH_HOME.trim() !== ""
|
|
280
|
-
? resolve(env.DSH_HOME.trim())
|
|
281
|
-
: resolve(homedir(), ".dsh");
|
|
282
|
-
return resolve(dshHome, "odai", "memory", "store.json");
|
|
198
|
+
const dshHome = typeof env.DSH_HOME === "string" && env.DSH_HOME.trim() !== "" ? resolve(env.DSH_HOME.trim()) : resolve(homedir(), ".dsh");
|
|
199
|
+
return resolve(dshHome, "odai", "memory", "store.json");
|
|
283
200
|
}
|
|
284
|
-
|
|
285
201
|
export function readMemoryStore(storePath) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
202
|
+
const identities = assertSafeStorePath(storePath);
|
|
203
|
+
let text;
|
|
204
|
+
try {
|
|
205
|
+
text = readRegularFileNoFollow(storePath);
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
assertDirectoryIdentities(identities);
|
|
209
|
+
if (errorCode(error) === "ENOENT")
|
|
210
|
+
return emptyStore();
|
|
211
|
+
throw new Error(`cannot read Odai semantic memory ${storePath}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
212
|
+
}
|
|
291
213
|
assertDirectoryIdentities(identities);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
`Odai semantic memory ${storePath} failed validation: ${error instanceof Error ? error.message : String(error)}`,
|
|
308
|
-
{ cause: error },
|
|
309
|
-
);
|
|
310
|
-
}
|
|
214
|
+
let parsed;
|
|
215
|
+
try {
|
|
216
|
+
parsed = JSON.parse(text);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
throw new MemoryStoreValidationError(`Odai semantic memory ${storePath} is not valid JSON`, { cause: error });
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
return validateStore(parsed, `Odai semantic memory ${storePath}`);
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
if (error instanceof MemoryStoreValidationError)
|
|
226
|
+
throw error;
|
|
227
|
+
throw new MemoryStoreValidationError(`Odai semantic memory ${storePath} failed validation: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
228
|
+
}
|
|
311
229
|
}
|
|
312
|
-
|
|
313
230
|
function writeMemoryStore(storePath, store) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
try {
|
|
322
|
-
let fd;
|
|
231
|
+
const value = validateStore(store, "Odai semantic memory write");
|
|
232
|
+
const parent = dirname(storePath);
|
|
233
|
+
assertSafeStorePath(storePath);
|
|
234
|
+
mkdirSync(parent, { recursive: true, mode: 0o700 });
|
|
235
|
+
const identities = assertSafeStorePath(storePath);
|
|
236
|
+
const temporary = `${storePath}.tmp-${process.pid}-${randomUUID()}`;
|
|
237
|
+
const noFollow = typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
|
|
323
238
|
try {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
239
|
+
let fd;
|
|
240
|
+
try {
|
|
241
|
+
fd = openSync(temporary, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | noFollow, 0o600);
|
|
242
|
+
writeFileSync(fd, `${JSON.stringify(value, null, 2)}\n`, { encoding: "utf8" });
|
|
243
|
+
fsyncSync(fd);
|
|
244
|
+
}
|
|
245
|
+
finally {
|
|
246
|
+
if (fd !== undefined)
|
|
247
|
+
closeSync(fd);
|
|
248
|
+
}
|
|
249
|
+
assertSafeStorePath(storePath);
|
|
250
|
+
assertDirectoryIdentities(identities);
|
|
251
|
+
renameSync(temporary, storePath);
|
|
252
|
+
assertDirectoryIdentities(identities);
|
|
329
253
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
} finally {
|
|
335
|
-
rmSync(temporary, { force: true });
|
|
336
|
-
}
|
|
337
|
-
return value;
|
|
254
|
+
finally {
|
|
255
|
+
rmSync(temporary, { force: true });
|
|
256
|
+
}
|
|
257
|
+
return value;
|
|
338
258
|
}
|
|
339
|
-
|
|
340
259
|
export function mutateMemoryStore(storePath, mutate) {
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
358
|
-
const outcome = mutate(mutable);
|
|
359
|
-
if (!outcome || outcome.changed !== true) return Object.freeze({ store: current, ...(outcome ?? {}) });
|
|
360
|
-
const store = writeMemoryStore(storePath, mutable);
|
|
361
|
-
return Object.freeze({ ...outcome, changed: true, store });
|
|
362
|
-
} finally {
|
|
363
|
-
releaseLock();
|
|
364
|
-
}
|
|
260
|
+
if (typeof mutate !== "function")
|
|
261
|
+
throw new TypeError("memory mutator must be a function");
|
|
262
|
+
const identities = assertSafeStorePath(storePath);
|
|
263
|
+
const releaseLock = acquireOwnedStoreLock(storePath, "Odai semantic memory");
|
|
264
|
+
try {
|
|
265
|
+
assertDirectoryIdentities(identities);
|
|
266
|
+
const current = readMemoryStore(storePath);
|
|
267
|
+
const mutable = { schemaVersion: MEMORY_STORE_SCHEMA_VERSION, settings: { ...current.settings }, entries: current.entries.map((entry) => ({ ...entry, scope: { ...entry.scope }, supersedes: [...entry.supersedes], conflictsWith: [...entry.conflictsWith], provenance: entry.provenance.map((source) => ({ ...source })) })) };
|
|
268
|
+
const outcome = mutate(mutable);
|
|
269
|
+
if (!outcome || outcome.changed !== true)
|
|
270
|
+
return Object.freeze({ store: current, ...outcome });
|
|
271
|
+
const store = writeMemoryStore(storePath, mutable);
|
|
272
|
+
return Object.freeze({ ...outcome, changed: true, store });
|
|
273
|
+
}
|
|
274
|
+
finally {
|
|
275
|
+
releaseLock();
|
|
276
|
+
}
|
|
365
277
|
}
|
|
366
|
-
|
|
367
278
|
export function resetMemoryStore(storePath) {
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
}
|
|
380
|
-
} finally {
|
|
381
|
-
releaseLock();
|
|
382
|
-
}
|
|
279
|
+
const identities = assertSafeStorePath(storePath);
|
|
280
|
+
const releaseLock = acquireOwnedStoreLock(storePath, "Odai semantic memory");
|
|
281
|
+
try {
|
|
282
|
+
assertSafeStorePath(storePath);
|
|
283
|
+
assertDirectoryIdentities(identities);
|
|
284
|
+
rmSync(storePath, { force: true });
|
|
285
|
+
assertDirectoryIdentities(identities);
|
|
286
|
+
return writeMemoryStore(storePath, { schemaVersion: MEMORY_STORE_SCHEMA_VERSION, settings: {}, entries: [] });
|
|
287
|
+
}
|
|
288
|
+
finally {
|
|
289
|
+
releaseLock();
|
|
290
|
+
}
|
|
383
291
|
}
|
|
384
|
-
|
|
385
292
|
export function effectiveMemorySettings(storePath, configured = {}) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
mode: store.settings.mode ?? configuredMode,
|
|
391
|
-
source: store.settings.mode === undefined ? "deployment-default" : "persisted",
|
|
392
|
-
});
|
|
293
|
+
const configuredMode = validateMode(configured.mode ?? DEFAULT_MEMORY_SETTINGS.mode, "config.memory.mode");
|
|
294
|
+
const store = readMemoryStore(storePath);
|
|
295
|
+
if (configuredMode === "off")
|
|
296
|
+
return Object.freeze({ mode: "off", source: "deployment-config" });
|
|
297
|
+
return Object.freeze({ mode: store.settings.mode ?? configuredMode, source: store.settings.mode === undefined ? "deployment-default" : "persisted" });
|
|
393
298
|
}
|
|
394
|
-
|
|
395
|
-
export function globalMemoryScope() {
|
|
396
|
-
return Object.freeze({ kind: "global", key: "global", label: "global" });
|
|
397
|
-
}
|
|
398
|
-
|
|
299
|
+
export function globalMemoryScope() { return Object.freeze({ kind: "global", key: "global", label: "global" }); }
|
|
399
300
|
export function projectMemoryScope(cwd) {
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
label: basename(canonical) || "project"
|
|
412
|
-
});
|
|
301
|
+
if (typeof cwd !== "string" || cwd.trim() === "")
|
|
302
|
+
return undefined;
|
|
303
|
+
let canonical;
|
|
304
|
+
try {
|
|
305
|
+
canonical = realpathSync.native(resolve(cwd.trim()));
|
|
306
|
+
if (!lstatSync(canonical).isDirectory())
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
return Object.freeze({ kind: "project", key: hash(canonical), label: basename(canonical) || "project" });
|
|
413
313
|
}
|
|
414
|
-
|
|
415
314
|
function eventSeqFor(agent, messageId) {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
export function directUserProvenance({ agent, message, turn, excerpt, extraction, now = Date.now() }) {
|
|
426
|
-
const sessionId = agent?.session?.header?.id;
|
|
427
|
-
const messageId = message?.id;
|
|
428
|
-
if (typeof sessionId !== "string" || sessionId === "" || typeof messageId !== "string" || messageId === "") {
|
|
315
|
+
const events = agent?.session?.events;
|
|
316
|
+
if (!Array.isArray(events))
|
|
317
|
+
return undefined;
|
|
318
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
319
|
+
const event = events[index];
|
|
320
|
+
if (event?.type === "user/message" && event.data?.id === messageId && Number.isSafeInteger(event.seq))
|
|
321
|
+
return event.seq;
|
|
322
|
+
}
|
|
429
323
|
return undefined;
|
|
430
|
-
}
|
|
431
|
-
if (!Number.isSafeInteger(turn) || turn < 0) return undefined;
|
|
432
|
-
const eventSeq = eventSeqFor(agent, messageId);
|
|
433
|
-
return Object.freeze({
|
|
434
|
-
sourceKind: "direct-user",
|
|
435
|
-
sessionHash: hash(sessionId),
|
|
436
|
-
messageHash: hash(messageId),
|
|
437
|
-
turn,
|
|
438
|
-
...(eventSeq === undefined ? {} : { eventSeq }),
|
|
439
|
-
excerptSha256: hash(excerpt),
|
|
440
|
-
observedAt: now,
|
|
441
|
-
extraction,
|
|
442
|
-
extractorVersion: MEMORY_EXTRACTOR_VERSION,
|
|
443
|
-
});
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
export function memoryRecordId(scope, category, subject, value) {
|
|
447
|
-
return `mem-${hash(JSON.stringify([scope.kind, scope.key, category, subject, value])).slice(0, 32)}`;
|
|
448
324
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
325
|
+
export function directUserProvenance(options) {
|
|
326
|
+
const { agent, message, turn, excerpt, extraction, now = Date.now() } = options;
|
|
327
|
+
const sessionId = agent?.session?.header?.id;
|
|
328
|
+
const messageId = message?.id;
|
|
329
|
+
if (typeof sessionId !== "string" || sessionId === "" || typeof messageId !== "string" || messageId === "")
|
|
330
|
+
return undefined;
|
|
331
|
+
if (typeof turn !== "number" || !Number.isSafeInteger(turn) || turn < 0)
|
|
332
|
+
return undefined;
|
|
333
|
+
const eventSeq = eventSeqFor(agent, messageId);
|
|
334
|
+
return Object.freeze({ sourceKind: "direct-user", sessionHash: hash(sessionId), messageHash: hash(messageId), turn, ...(eventSeq === undefined ? {} : { eventSeq }), excerptSha256: hash(excerpt), observedAt: now, extraction, extractorVersion: MEMORY_EXTRACTOR_VERSION });
|
|
452
335
|
}
|
|
336
|
+
export function memoryRecordId(scope, category, subject, value) { return `mem-${hash(JSON.stringify([scope.kind, scope.key, category, subject, value])).slice(0, 32)}`; }
|
|
337
|
+
export function memoryValueDigest(value) { return hash(value); }
|
|
338
|
+
//# sourceMappingURL=semantic-memory-store.mjs.map
|