@noopolis/mneme 0.1.0
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 +83 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +46 -0
- package/dist/contract/index.d.ts +3 -0
- package/dist/contract/index.d.ts.map +1 -0
- package/dist/contract/index.js +2 -0
- package/dist/contract/toolDescriptors.d.ts +14 -0
- package/dist/contract/toolDescriptors.d.ts.map +1 -0
- package/dist/contract/toolDescriptors.js +98 -0
- package/dist/contract/types.d.ts +262 -0
- package/dist/contract/types.d.ts.map +1 -0
- package/dist/contract/types.js +1 -0
- package/dist/identity/ids.d.ts +9 -0
- package/dist/identity/ids.d.ts.map +1 -0
- package/dist/identity/ids.js +25 -0
- package/dist/identity/index.d.ts +3 -0
- package/dist/identity/index.d.ts.map +1 -0
- package/dist/identity/index.js +2 -0
- package/dist/identity/scope.d.ts +24 -0
- package/dist/identity/scope.d.ts.map +1 -0
- package/dist/identity/scope.js +123 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/kernel/index.d.ts +3 -0
- package/dist/kernel/index.d.ts.map +1 -0
- package/dist/kernel/index.js +2 -0
- package/dist/kernel/kernel.d.ts +19 -0
- package/dist/kernel/kernel.d.ts.map +1 -0
- package/dist/kernel/kernel.js +318 -0
- package/dist/kernel/support.d.ts +66 -0
- package/dist/kernel/support.d.ts.map +1 -0
- package/dist/kernel/support.js +207 -0
- package/dist/mcp/config.d.ts +23 -0
- package/dist/mcp/config.d.ts.map +1 -0
- package/dist/mcp/config.js +76 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +3 -0
- package/dist/mcp/schemas.d.ts +150 -0
- package/dist/mcp/schemas.d.ts.map +1 -0
- package/dist/mcp/schemas.js +54 -0
- package/dist/mcp/server.d.ts +5 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +45 -0
- package/dist/policy/index.d.ts +2 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +1 -0
- package/dist/policy/policy.d.ts +9 -0
- package/dist/policy/policy.d.ts.map +1 -0
- package/dist/policy/policy.js +123 -0
- package/dist/recall/index.d.ts +2 -0
- package/dist/recall/index.d.ts.map +1 -0
- package/dist/recall/index.js +1 -0
- package/dist/recall/recall.d.ts +28 -0
- package/dist/recall/recall.d.ts.map +1 -0
- package/dist/recall/recall.js +178 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/runtime.d.ts +19 -0
- package/dist/runtime/runtime.d.ts.map +1 -0
- package/dist/runtime/runtime.js +129 -0
- package/dist/runtime/support.d.ts +52 -0
- package/dist/runtime/support.d.ts.map +1 -0
- package/dist/runtime/support.js +229 -0
- package/dist/store/index.d.ts +3 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +2 -0
- package/dist/store/sqliteIndex.d.ts +38 -0
- package/dist/store/sqliteIndex.d.ts.map +1 -0
- package/dist/store/sqliteIndex.js +270 -0
- package/dist/store/store.d.ts +27 -0
- package/dist/store/store.d.ts.map +1 -0
- package/dist/store/store.js +114 -0
- package/package.json +53 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { sanitizePrincipalQualifier } from "./ids.js";
|
|
2
|
+
const roomPrincipal = (agentId, context) => {
|
|
3
|
+
if (!context?.networkId || !context.roomId) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
return {
|
|
7
|
+
agentId,
|
|
8
|
+
scope: "room",
|
|
9
|
+
qualifier: `${context.networkId}:${context.roomId}`
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
const teamPrincipal = (agentId, context) => {
|
|
13
|
+
if (!context?.teamId) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
agentId,
|
|
18
|
+
scope: "team",
|
|
19
|
+
qualifier: context.teamId
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
const pairPrincipals = (agentId, context) => {
|
|
23
|
+
const peers = context?.pairPeers ?? [];
|
|
24
|
+
return [...new Set(peers
|
|
25
|
+
.map((peer) => sanitizePrincipalQualifier(peer))
|
|
26
|
+
.filter((peer) => Boolean(peer)))]
|
|
27
|
+
.sort()
|
|
28
|
+
.map((peer) => ({
|
|
29
|
+
agentId,
|
|
30
|
+
scope: "pair",
|
|
31
|
+
qualifier: peer
|
|
32
|
+
}));
|
|
33
|
+
};
|
|
34
|
+
const taskPrincipal = (agentId, context) => {
|
|
35
|
+
if (!context?.taskId) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
agentId,
|
|
40
|
+
scope: "task",
|
|
41
|
+
qualifier: context.taskId
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
const rolePrincipal = (agentId, context) => {
|
|
45
|
+
if (!context?.roleId) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
agentId,
|
|
50
|
+
scope: "role",
|
|
51
|
+
qualifier: context.roleId
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
export const resolveScopePlan = (input) => {
|
|
55
|
+
const global = {
|
|
56
|
+
agentId: input.agentId,
|
|
57
|
+
scope: "global"
|
|
58
|
+
};
|
|
59
|
+
const fromPeer = input.context?.from;
|
|
60
|
+
const fromPair = fromPeer ? [{
|
|
61
|
+
agentId: input.agentId,
|
|
62
|
+
scope: "pair",
|
|
63
|
+
qualifier: sanitizePrincipalQualifier(fromPeer) ?? fromPeer.trim().toLowerCase()
|
|
64
|
+
}] : [];
|
|
65
|
+
const room = roomPrincipal(input.agentId, input.context);
|
|
66
|
+
const team = teamPrincipal(input.agentId, input.context);
|
|
67
|
+
const task = taskPrincipal(input.agentId, input.context);
|
|
68
|
+
const role = rolePrincipal(input.agentId, input.context);
|
|
69
|
+
const pairEntries = pairPrincipals(input.agentId, input.context);
|
|
70
|
+
const pairPrincipal = fromPair[0] ?? pairEntries[0];
|
|
71
|
+
const isMessage = input.wake.kind === "message" || input.wake.kind === "manual";
|
|
72
|
+
const activePrincipal = ((isMessage && fromPair.length > 0) ? fromPair[0]
|
|
73
|
+
: room ? room
|
|
74
|
+
: team ? team
|
|
75
|
+
: task ? task
|
|
76
|
+
: role ? role
|
|
77
|
+
: global);
|
|
78
|
+
const readableScopes = [
|
|
79
|
+
global,
|
|
80
|
+
activePrincipal,
|
|
81
|
+
room,
|
|
82
|
+
team,
|
|
83
|
+
task,
|
|
84
|
+
role
|
|
85
|
+
].filter((value) => Boolean(value));
|
|
86
|
+
if (isMessage && (pairEntries.length > 0 || pairPrincipal)) {
|
|
87
|
+
const pairs = [...pairEntries, ...(pairPrincipal ? [pairPrincipal] : [])];
|
|
88
|
+
readableScopes.push(...pairs);
|
|
89
|
+
}
|
|
90
|
+
const candidateScopes = [
|
|
91
|
+
global,
|
|
92
|
+
roomPrincipal(input.agentId, input.context),
|
|
93
|
+
teamPrincipal(input.agentId, input.context),
|
|
94
|
+
...pairEntries,
|
|
95
|
+
...(fromPair[0] ? [fromPair[0]] : []),
|
|
96
|
+
taskPrincipal(input.agentId, input.context),
|
|
97
|
+
rolePrincipal(input.agentId, input.context)
|
|
98
|
+
].filter((value) => Boolean(value));
|
|
99
|
+
const deniedScopes = [];
|
|
100
|
+
return {
|
|
101
|
+
activePrincipal,
|
|
102
|
+
readableScopes,
|
|
103
|
+
candidateScopes,
|
|
104
|
+
deniedScopes
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
export const readMemoryContext = (event) => {
|
|
108
|
+
const context = event.context ?? {};
|
|
109
|
+
const participants = context.participants;
|
|
110
|
+
const pairPeers = context.pairPeers ?? participants;
|
|
111
|
+
const resolvedParticipants = participants ?? pairPeers;
|
|
112
|
+
return {
|
|
113
|
+
from: event.from ?? context.from,
|
|
114
|
+
networkId: context.networkId,
|
|
115
|
+
roomId: context.roomId,
|
|
116
|
+
teamId: context.teamId,
|
|
117
|
+
taskId: context.taskId,
|
|
118
|
+
roleId: context.roleId,
|
|
119
|
+
pairPeers,
|
|
120
|
+
artifactPaths: context.artifactPaths,
|
|
121
|
+
participants: resolvedParticipants
|
|
122
|
+
};
|
|
123
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./contract/index.js";
|
|
2
|
+
export * from "./identity/index.js";
|
|
3
|
+
export * from "./kernel/index.js";
|
|
4
|
+
export * from "./policy/index.js";
|
|
5
|
+
export * from "./recall/index.js";
|
|
6
|
+
export * from "./runtime/index.js";
|
|
7
|
+
export * from "./store/index.js";
|
|
8
|
+
export * from "./mcp/index.js";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./contract/index.js";
|
|
2
|
+
export * from "./identity/index.js";
|
|
3
|
+
export * from "./kernel/index.js";
|
|
4
|
+
export * from "./policy/index.js";
|
|
5
|
+
export * from "./recall/index.js";
|
|
6
|
+
export * from "./runtime/index.js";
|
|
7
|
+
export * from "./store/index.js";
|
|
8
|
+
export * from "./mcp/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/kernel/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { MemoryKernel, MemoryToolCall, MemoryToolResult } from "../contract/types.js";
|
|
2
|
+
export interface MemoryKernelConfig {
|
|
3
|
+
runtimeHomePath: string;
|
|
4
|
+
source?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare class JsonlMemoryKernel implements MemoryKernel {
|
|
7
|
+
private readonly config;
|
|
8
|
+
private readonly store;
|
|
9
|
+
private readonly index;
|
|
10
|
+
private readonly source;
|
|
11
|
+
constructor(config: MemoryKernelConfig);
|
|
12
|
+
search(call: MemoryToolCall): Promise<MemoryToolResult>;
|
|
13
|
+
locate(call: MemoryToolCall): Promise<MemoryToolResult>;
|
|
14
|
+
register(call: MemoryToolCall): Promise<MemoryToolResult>;
|
|
15
|
+
summarize(call: MemoryToolCall): Promise<MemoryToolResult>;
|
|
16
|
+
forget(call: MemoryToolCall): Promise<MemoryToolResult>;
|
|
17
|
+
}
|
|
18
|
+
export declare const createMemoryKernel: (config: MemoryKernelConfig) => MemoryKernel;
|
|
19
|
+
//# sourceMappingURL=kernel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kernel.d.ts","sourceRoot":"","sources":["../../src/kernel/kernel.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAEV,YAAY,EACZ,cAAc,EACd,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AA0B9B,MAAM,WAAW,kBAAkB;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,iBAAkB,YAAW,YAAY;IAKxC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAJnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEH,MAAM,EAAE,kBAAkB;IAMjD,MAAM,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmEvD,MAAM,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA+FvD,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgDzD,SAAS,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAuE1D,MAAM,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAgD9D;AAED,eAAO,MAAM,kBAAkB,GAAI,QAAQ,kBAAkB,KAAG,YAA6C,CAAC"}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import { JsonlMemoryStore } from "../store/store.js";
|
|
2
|
+
import { memoryPolicy } from "../policy/policy.js";
|
|
3
|
+
import { createMemoryIndex } from "../store/sqliteIndex.js";
|
|
4
|
+
import { runRecall } from "../recall/recall.js";
|
|
5
|
+
import { asNumber, collectTombstones, hasInvalidV1Envelope, decide, eventText, isForgetArguments, isLocateArguments, isRegisterArguments, isRecallableMemoryEvent, isSearchArguments, isSummarizeArguments, makeAudit, matchesQuery, makeLocateResult, makeSearchResult, malformed, unavailable, policyText, resolveScope, locateCandidateId, sanitizePrincipal, } from "./support.js";
|
|
6
|
+
export class JsonlMemoryKernel {
|
|
7
|
+
config;
|
|
8
|
+
store;
|
|
9
|
+
index;
|
|
10
|
+
source;
|
|
11
|
+
constructor(config) {
|
|
12
|
+
this.config = config;
|
|
13
|
+
this.store = new JsonlMemoryStore(config.runtimeHomePath);
|
|
14
|
+
this.index = createMemoryIndex({ runtimeHomePath: config.runtimeHomePath });
|
|
15
|
+
this.source = this.config.source ?? `mneme/${this.config.runtimeHomePath}`;
|
|
16
|
+
}
|
|
17
|
+
async search(call) {
|
|
18
|
+
const startAt = Date.now();
|
|
19
|
+
if (hasInvalidV1Envelope(call.envelope.version)) {
|
|
20
|
+
return malformed(call, "memory.search", "unsupported envelope", startAt);
|
|
21
|
+
}
|
|
22
|
+
const args = call.arguments;
|
|
23
|
+
if (!isSearchArguments(args)) {
|
|
24
|
+
return malformed(call, "memory.search", "memory.search requires { scope, query }", startAt);
|
|
25
|
+
}
|
|
26
|
+
const requester = sanitizePrincipal(call.envelope.principal);
|
|
27
|
+
const scope = resolveScope(args.scope, requester);
|
|
28
|
+
const limit = asNumber(args.limit) || 20;
|
|
29
|
+
try {
|
|
30
|
+
const allEvents = await this.store.read();
|
|
31
|
+
await this.index.rebuildFromEvents(allEvents);
|
|
32
|
+
const indexed = await this.index.query({
|
|
33
|
+
allowedScopes: scope === "all" ? undefined : [scope],
|
|
34
|
+
query: args.query,
|
|
35
|
+
limit: Math.max(limit * 4, 40)
|
|
36
|
+
});
|
|
37
|
+
const events = indexed.map((entry) => entry.event);
|
|
38
|
+
const tombstones = collectTombstones(allEvents);
|
|
39
|
+
const filteredEvents = events
|
|
40
|
+
.filter((event) => isRecallableMemoryEvent(event) && !tombstones.has(event.id))
|
|
41
|
+
.filter((event) => matchesQuery(event, args.query));
|
|
42
|
+
const selections = scope === "all"
|
|
43
|
+
? filteredEvents.map((event) => ({
|
|
44
|
+
event,
|
|
45
|
+
decision: memoryPolicy({ request: requester, candidate: event, activeScope: requester }).decision
|
|
46
|
+
})).filter((entry) => entry.decision !== "deny")
|
|
47
|
+
.sort((left, right) => Date.parse(right.event.createdAt) - Date.parse(left.event.createdAt))
|
|
48
|
+
: runRecall({
|
|
49
|
+
actor: requester,
|
|
50
|
+
scopeIds: [scope],
|
|
51
|
+
events: filteredEvents,
|
|
52
|
+
query: args.query,
|
|
53
|
+
maxTokens: limit * 80
|
|
54
|
+
}).selected.map((entry) => ({ event: entry.event, decision: entry.decision }));
|
|
55
|
+
const selected = selections.slice(0, limit);
|
|
56
|
+
if (selected.length === 0) {
|
|
57
|
+
return {
|
|
58
|
+
request_id: call.request_id,
|
|
59
|
+
tool: "memory.search",
|
|
60
|
+
decision: "deny",
|
|
61
|
+
content: [],
|
|
62
|
+
audit: makeAudit(call, events, startAt)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
request_id: call.request_id,
|
|
67
|
+
tool: "memory.search",
|
|
68
|
+
decision: decide(selected.map((entry) => entry.decision)),
|
|
69
|
+
content: selected.map((entry) => makeSearchResult(entry.decision, entry.event)),
|
|
70
|
+
audit: makeAudit(call, selected.map((entry) => entry.event), startAt)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
return unavailable(call, "memory.search", String(error instanceof Error ? error.message : error), startAt);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async locate(call) {
|
|
78
|
+
const startAt = Date.now();
|
|
79
|
+
if (hasInvalidV1Envelope(call.envelope.version)) {
|
|
80
|
+
return malformed(call, "memory.locate", "unsupported envelope", startAt);
|
|
81
|
+
}
|
|
82
|
+
const args = call.arguments;
|
|
83
|
+
if (!isLocateArguments(args)) {
|
|
84
|
+
return malformed(call, "memory.locate", "memory.locate requires { query }", startAt);
|
|
85
|
+
}
|
|
86
|
+
const requester = sanitizePrincipal(call.envelope.principal);
|
|
87
|
+
const limit = asNumber(args.limit) || 5;
|
|
88
|
+
try {
|
|
89
|
+
const allEvents = await this.store.read();
|
|
90
|
+
await this.index.rebuildFromEvents(allEvents);
|
|
91
|
+
const query = args.query;
|
|
92
|
+
const candidateEvents = (await this.index.query({
|
|
93
|
+
query,
|
|
94
|
+
limit: Math.max(limit * 8, 40)
|
|
95
|
+
})).map((entry) => entry.event)
|
|
96
|
+
.filter((event) => isRecallableMemoryEvent(event) && !collectTombstones(allEvents).has(event.id));
|
|
97
|
+
const tokens = query.toLowerCase()
|
|
98
|
+
.split(/\W+/u)
|
|
99
|
+
.filter((value) => value.length > 3);
|
|
100
|
+
const byHandle = new Map();
|
|
101
|
+
for (const event of candidateEvents) {
|
|
102
|
+
const decision = memoryPolicy({
|
|
103
|
+
request: requester,
|
|
104
|
+
candidate: event,
|
|
105
|
+
activeScope: requester
|
|
106
|
+
}).decision;
|
|
107
|
+
if (decision === "deny" || decision === "unavailable" || decision === "malformed_request") {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const score = tokens.filter((token) => eventText(event).toLowerCase().includes(token)).length;
|
|
111
|
+
const key = locateCandidateId(event);
|
|
112
|
+
const next = byHandle.get(key);
|
|
113
|
+
const handle = {
|
|
114
|
+
decision,
|
|
115
|
+
event,
|
|
116
|
+
score,
|
|
117
|
+
eventIds: [event.id],
|
|
118
|
+
scope: event.scope
|
|
119
|
+
};
|
|
120
|
+
if (!next) {
|
|
121
|
+
byHandle.set(key, handle);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
next.eventIds.push(event.id);
|
|
125
|
+
next.score = Math.max(next.score, score);
|
|
126
|
+
}
|
|
127
|
+
const selected = [...byHandle.values()]
|
|
128
|
+
.sort((left, right) => right.score - left.score || Date.parse(right.event.createdAt) - Date.parse(left.event.createdAt))
|
|
129
|
+
.slice(0, limit);
|
|
130
|
+
if (selected.length === 0) {
|
|
131
|
+
return { request_id: call.request_id, tool: "memory.locate", decision: "deny", content: [], audit: makeAudit(call, [], startAt) };
|
|
132
|
+
}
|
|
133
|
+
const locatedEvent = await this.store.append({
|
|
134
|
+
type: "memory.located",
|
|
135
|
+
principal: requester,
|
|
136
|
+
scope: resolveScope("current", requester),
|
|
137
|
+
visibility: "private",
|
|
138
|
+
source: this.source,
|
|
139
|
+
content: {
|
|
140
|
+
kind: "text",
|
|
141
|
+
text: `Located ${selected.length} memory candidate(s).`
|
|
142
|
+
},
|
|
143
|
+
tags: ["locate"],
|
|
144
|
+
entities: [requester.agentId, requester.scope],
|
|
145
|
+
sensitivity: "normal",
|
|
146
|
+
parentEventIds: selected.flatMap((entry) => entry.eventIds)
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
request_id: call.request_id,
|
|
150
|
+
tool: "memory.locate",
|
|
151
|
+
decision: "locate_only",
|
|
152
|
+
content: selected.map((entry) => makeLocateResult(entry)),
|
|
153
|
+
audit: makeAudit(call, [locatedEvent, ...selected.map((entry) => entry.event)], startAt)
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return unavailable(call, "memory.locate", String(error instanceof Error ? error.message : error), startAt);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async register(call) {
|
|
161
|
+
const startAt = Date.now();
|
|
162
|
+
if (hasInvalidV1Envelope(call.envelope.version)) {
|
|
163
|
+
return malformed(call, "memory.register", "unsupported envelope", startAt);
|
|
164
|
+
}
|
|
165
|
+
const args = call.arguments;
|
|
166
|
+
if (!isRegisterArguments(args)) {
|
|
167
|
+
return malformed(call, "memory.register", "memory.register requires evidence and content fields", startAt);
|
|
168
|
+
}
|
|
169
|
+
const principal = args.principal
|
|
170
|
+
? sanitizePrincipal(args.principal)
|
|
171
|
+
: sanitizePrincipal(call.envelope.principal);
|
|
172
|
+
try {
|
|
173
|
+
const event = await this.store.append({
|
|
174
|
+
type: "memory.registered",
|
|
175
|
+
principal,
|
|
176
|
+
scope: resolveScope(args.scope, principal),
|
|
177
|
+
visibility: args.visibility,
|
|
178
|
+
source: args.source_type,
|
|
179
|
+
content: args.content,
|
|
180
|
+
tags: ["registered", principal.scope, args.visibility],
|
|
181
|
+
entities: [principal.agentId, principal.scope],
|
|
182
|
+
sensitivity: args.sensitivity,
|
|
183
|
+
parentEventIds: args.evidence_event_ids,
|
|
184
|
+
confidence: args.confidence
|
|
185
|
+
});
|
|
186
|
+
return {
|
|
187
|
+
request_id: call.request_id,
|
|
188
|
+
tool: "memory.register",
|
|
189
|
+
decision: "allow_raw",
|
|
190
|
+
content: [{
|
|
191
|
+
kind: "memory",
|
|
192
|
+
text: "Registered memory with explicit evidence.",
|
|
193
|
+
event_ids: [event.id],
|
|
194
|
+
scope: event.scope,
|
|
195
|
+
principal: event.principal,
|
|
196
|
+
redactions: [],
|
|
197
|
+
confidence: args.confidence
|
|
198
|
+
}],
|
|
199
|
+
audit: makeAudit(call, [event], startAt)
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
return unavailable(call, "memory.register", String(error instanceof Error ? error.message : error), startAt);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async summarize(call) {
|
|
207
|
+
const startAt = Date.now();
|
|
208
|
+
if (hasInvalidV1Envelope(call.envelope.version)) {
|
|
209
|
+
return malformed(call, "memory.summarize", "unsupported envelope", startAt);
|
|
210
|
+
}
|
|
211
|
+
const args = call.arguments;
|
|
212
|
+
if (!isSummarizeArguments(args)) {
|
|
213
|
+
return malformed(call, "memory.summarize", "memory.summarize requires { scope }", startAt);
|
|
214
|
+
}
|
|
215
|
+
const requester = sanitizePrincipal(call.envelope.principal);
|
|
216
|
+
const scope = resolveScope(args.scope, requester);
|
|
217
|
+
const horizon = Math.min(asNumber(args.horizon) || 12, 40);
|
|
218
|
+
try {
|
|
219
|
+
const events = await this.store.read({ scope });
|
|
220
|
+
const tombstones = collectTombstones(events);
|
|
221
|
+
const sourceIds = [];
|
|
222
|
+
const lines = events
|
|
223
|
+
.filter((event) => isRecallableMemoryEvent(event) && !tombstones.has(event.id))
|
|
224
|
+
.map((event) => ({
|
|
225
|
+
event,
|
|
226
|
+
decision: memoryPolicy({ request: requester, candidate: event, activeScope: requester }).decision
|
|
227
|
+
}))
|
|
228
|
+
.filter((entry) => entry.decision !== "deny")
|
|
229
|
+
.slice(0, horizon)
|
|
230
|
+
.map((entry) => {
|
|
231
|
+
sourceIds.push(entry.event.id);
|
|
232
|
+
return `${entry.event.createdAt}: ${policyText(entry.decision, eventText(entry.event))}`;
|
|
233
|
+
});
|
|
234
|
+
if (sourceIds.length === 0) {
|
|
235
|
+
return { request_id: call.request_id, tool: "memory.summarize", decision: "deny", content: [], audit: makeAudit(call, [], startAt) };
|
|
236
|
+
}
|
|
237
|
+
const summary = await this.store.append({
|
|
238
|
+
type: "memory.summarized",
|
|
239
|
+
principal: requester,
|
|
240
|
+
scope,
|
|
241
|
+
visibility: "private",
|
|
242
|
+
source: this.source,
|
|
243
|
+
content: { kind: "text", text: lines.join("\n") },
|
|
244
|
+
tags: ["summary", ...sourceIds],
|
|
245
|
+
entities: [requester.agentId, requester.scope],
|
|
246
|
+
sensitivity: "normal",
|
|
247
|
+
confidence: 1,
|
|
248
|
+
parentEventIds: sourceIds
|
|
249
|
+
});
|
|
250
|
+
return {
|
|
251
|
+
request_id: call.request_id,
|
|
252
|
+
tool: "memory.summarize",
|
|
253
|
+
decision: "allow_summary",
|
|
254
|
+
content: [{
|
|
255
|
+
kind: "narrative",
|
|
256
|
+
text: lines.join("\n"),
|
|
257
|
+
event_ids: sourceIds,
|
|
258
|
+
scope,
|
|
259
|
+
principal: requester,
|
|
260
|
+
redactions: [],
|
|
261
|
+
confidence: 1
|
|
262
|
+
}],
|
|
263
|
+
audit: makeAudit(call, [summary], startAt)
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
return unavailable(call, "memory.summarize", String(error instanceof Error ? error.message : error), startAt);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
async forget(call) {
|
|
271
|
+
const startAt = Date.now();
|
|
272
|
+
if (hasInvalidV1Envelope(call.envelope.version)) {
|
|
273
|
+
return malformed(call, "memory.forget", "unsupported envelope", startAt);
|
|
274
|
+
}
|
|
275
|
+
const args = call.arguments;
|
|
276
|
+
if (!isForgetArguments(args)) {
|
|
277
|
+
return malformed(call, "memory.forget", "memory.forget requires { scope, event_ids }", startAt);
|
|
278
|
+
}
|
|
279
|
+
const requester = sanitizePrincipal(call.envelope.principal);
|
|
280
|
+
try {
|
|
281
|
+
const event = await this.store.append({
|
|
282
|
+
type: "memory.forgotten",
|
|
283
|
+
principal: requester,
|
|
284
|
+
scope: resolveScope(args.scope, requester),
|
|
285
|
+
visibility: "private",
|
|
286
|
+
source: this.source,
|
|
287
|
+
content: {
|
|
288
|
+
kind: "text",
|
|
289
|
+
text: `Tombstone for ${args.event_ids.length} event(s).`
|
|
290
|
+
},
|
|
291
|
+
tags: ["forget", "tombstone"],
|
|
292
|
+
entities: [requester.agentId, requester.scope],
|
|
293
|
+
sensitivity: "secret",
|
|
294
|
+
confidence: 1,
|
|
295
|
+
parentEventIds: args.event_ids
|
|
296
|
+
});
|
|
297
|
+
return {
|
|
298
|
+
request_id: call.request_id,
|
|
299
|
+
tool: "memory.forget",
|
|
300
|
+
decision: "allow_raw",
|
|
301
|
+
content: [{
|
|
302
|
+
kind: "memory",
|
|
303
|
+
text: `Tombstone written for ${args.event_ids.length} event(s).`,
|
|
304
|
+
event_ids: [event.id],
|
|
305
|
+
scope: event.scope,
|
|
306
|
+
principal: event.principal,
|
|
307
|
+
redactions: ["content-redacted"],
|
|
308
|
+
confidence: 1
|
|
309
|
+
}],
|
|
310
|
+
audit: makeAudit(call, [event], startAt)
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
return unavailable(call, "memory.forget", String(error instanceof Error ? error.message : error), startAt);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
export const createMemoryKernel = (config) => new JsonlMemoryKernel(config);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { MemoryDecision, MemoryEvent, MemoryEventType, MemoryContent, MemoryForgetArguments, MemoryLocateArguments, MemoryRegisterArguments, MemorySearchArguments, MemorySummarizeArguments, MemoryToolCall, MemoryToolAudit, MemoryToolCallEnvelope, MemoryToolDecision, MemoryToolName, MemoryToolResult, MemoryToolResultContent, MemoryVisibility, MemorySensitivity } from "../contract/types.js";
|
|
2
|
+
export interface CandidateHandle {
|
|
3
|
+
decision: MemoryDecision;
|
|
4
|
+
event: MemoryEvent;
|
|
5
|
+
score: number;
|
|
6
|
+
eventIds: string[];
|
|
7
|
+
scope: string;
|
|
8
|
+
}
|
|
9
|
+
export type MemoryResultItem = Omit<MemoryToolResultContent, "event_ids" | "redactions"> & {
|
|
10
|
+
event_ids: string[];
|
|
11
|
+
redactions: string[];
|
|
12
|
+
};
|
|
13
|
+
export declare const isPlainObject: (value: unknown) => value is Record<string, unknown>;
|
|
14
|
+
export declare const asNumber: (value: unknown) => number;
|
|
15
|
+
export declare const isVisibility: (value: unknown) => value is MemoryVisibility;
|
|
16
|
+
export declare const isSensitivity: (value: unknown) => value is MemorySensitivity;
|
|
17
|
+
export declare const isSearchArguments: (value: Record<string, unknown>) => value is Omit<MemorySearchArguments, "scope" | "query"> & {
|
|
18
|
+
scope: string;
|
|
19
|
+
query: string;
|
|
20
|
+
};
|
|
21
|
+
export declare const isLocateArguments: (value: Record<string, unknown>) => value is Omit<MemoryLocateArguments, "query"> & {
|
|
22
|
+
query: string;
|
|
23
|
+
};
|
|
24
|
+
export declare const isSummarizeArguments: (value: Record<string, unknown>) => value is Omit<MemorySummarizeArguments, "scope"> & {
|
|
25
|
+
scope: string;
|
|
26
|
+
};
|
|
27
|
+
export declare const isMemoryContent: (value: unknown) => value is MemoryContent;
|
|
28
|
+
export declare const isRegisterArguments: (value: unknown) => value is MemoryRegisterArguments;
|
|
29
|
+
export declare const isForgetArguments: (value: unknown) => value is MemoryForgetArguments;
|
|
30
|
+
export declare const makeAudit: (call: MemoryToolCall, sources: MemoryEvent[], startAt: number) => MemoryToolAudit;
|
|
31
|
+
export declare const malformed: (call: MemoryToolCall, tool: MemoryToolName, error: string, startAt: number) => MemoryToolResult;
|
|
32
|
+
export declare const unavailable: (call: MemoryToolCall, tool: MemoryToolName, error: string, startAt: number) => MemoryToolResult;
|
|
33
|
+
export declare const eventText: (event: MemoryEvent) => string;
|
|
34
|
+
export declare const resultKind: (kind: MemoryEventType | MemoryEvent["content"]["kind"]) => MemoryToolResultContent["kind"];
|
|
35
|
+
export declare const policyText: (decision: MemoryDecision, text: string) => string;
|
|
36
|
+
export declare const decide: (decisions: MemoryDecision[]) => MemoryToolDecision;
|
|
37
|
+
export declare const resolveScope: (scopeInput: string, requester: MemoryToolCallEnvelope["principal"]) => string;
|
|
38
|
+
export declare const sanitizePrincipal: (principal: MemoryToolCallEnvelope["principal"]) => {
|
|
39
|
+
qualifier: string | undefined;
|
|
40
|
+
agentId: string;
|
|
41
|
+
scope: "global" | "team" | "room" | "pair" | "task" | "role" | "artifact";
|
|
42
|
+
};
|
|
43
|
+
export declare const collectTombstones: (events: MemoryEvent[]) => Set<string>;
|
|
44
|
+
export declare const isRecallableMemoryEvent: (event: MemoryEvent) => boolean;
|
|
45
|
+
export declare const matchesQuery: (event: MemoryEvent, query: string) => boolean;
|
|
46
|
+
export declare const canExposeEventId: (decision: MemoryDecision) => boolean;
|
|
47
|
+
export declare const locateCandidateId: (event: MemoryEvent) => string;
|
|
48
|
+
export declare const hasInvalidV1Envelope: (version: string) => boolean;
|
|
49
|
+
export declare const makeSearchResult: (decision: MemoryDecision, event: MemoryEvent) => {
|
|
50
|
+
kind: "artifact" | "memory" | "claim" | "narrative" | "relationship" | "locate";
|
|
51
|
+
text: string;
|
|
52
|
+
event_ids: string[];
|
|
53
|
+
scope: string;
|
|
54
|
+
principal: import("../contract/types.js").MemoryPrincipalRef;
|
|
55
|
+
confidence: number;
|
|
56
|
+
redactions: string[];
|
|
57
|
+
};
|
|
58
|
+
export declare const makeLocateResult: (entry: CandidateHandle) => {
|
|
59
|
+
kind: "locate";
|
|
60
|
+
event_ids: string[];
|
|
61
|
+
scope: string;
|
|
62
|
+
principal: import("../contract/types.js").MemoryPrincipalRef;
|
|
63
|
+
confidence: number;
|
|
64
|
+
redactions: string[];
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=support.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"support.d.ts","sourceRoot":"","sources":["../../src/kernel/support.ts"],"names":[],"mappings":"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"}
|