@memoryrelay/plugin-memoryrelay-ai 0.15.6 → 0.16.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 +2 -3
- package/index.ts +472 -4849
- package/openclaw.plugin.json +41 -3
- package/package.json +1 -1
- package/skills/decision-tracking/SKILL.md +1 -1
- package/skills/entity-and-context/SKILL.md +1 -1
- package/skills/memory-workflow/SKILL.md +1 -1
- package/src/client/memoryrelay-client.ts +816 -0
- package/src/context/namespace-router.ts +19 -0
- package/src/context/request-context.ts +39 -0
- package/src/context/session-resolver.ts +93 -0
- package/src/filters/content-patterns.ts +32 -0
- package/src/filters/noise-patterns.ts +33 -0
- package/src/filters/non-interactive.ts +30 -0
- package/src/hooks/activity.ts +51 -0
- package/src/hooks/agent-end.ts +48 -0
- package/src/hooks/before-agent-start.ts +109 -0
- package/src/hooks/before-prompt-build.ts +46 -0
- package/src/hooks/compaction.ts +51 -0
- package/src/hooks/privacy.ts +44 -0
- package/src/hooks/session-lifecycle.ts +47 -0
- package/src/hooks/subagent.ts +62 -0
- package/src/pipelines/capture/content-strip.ts +14 -0
- package/src/pipelines/capture/dedup.ts +17 -0
- package/src/pipelines/capture/index.ts +13 -0
- package/src/pipelines/capture/message-filter.ts +16 -0
- package/src/pipelines/capture/store.ts +33 -0
- package/src/pipelines/capture/trigger-gate.ts +21 -0
- package/src/pipelines/capture/truncate.ts +16 -0
- package/src/pipelines/recall/format.ts +30 -0
- package/src/pipelines/recall/index.ts +12 -0
- package/src/pipelines/recall/rank.ts +40 -0
- package/src/pipelines/recall/scope-resolver.ts +20 -0
- package/src/pipelines/recall/search.ts +43 -0
- package/src/pipelines/recall/trigger-gate.ts +17 -0
- package/src/pipelines/runner.ts +25 -0
- package/src/pipelines/types.ts +157 -0
- package/src/tools/agent-tools.ts +127 -0
- package/src/tools/decision-tools.ts +309 -0
- package/src/tools/entity-tools.ts +215 -0
- package/src/tools/health-tools.ts +42 -0
- package/src/tools/memory-tools.ts +690 -0
- package/src/tools/pattern-tools.ts +250 -0
- package/src/tools/project-tools.ts +444 -0
- package/src/tools/session-tools.ts +195 -0
- package/src/tools/v2-tools.ts +228 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
+
import type { PluginConfig } from "../pipelines/types.js";
|
|
3
|
+
import type { MemoryRelayClient } from "../client/memoryrelay-client.js";
|
|
4
|
+
import type { SessionResolver } from "../context/session-resolver.js";
|
|
5
|
+
|
|
6
|
+
export function registerSessionTools(
|
|
7
|
+
api: OpenClawPluginApi,
|
|
8
|
+
config: PluginConfig,
|
|
9
|
+
client: MemoryRelayClient,
|
|
10
|
+
sessionResolver: SessionResolver,
|
|
11
|
+
isToolEnabled: (name: string) => boolean,
|
|
12
|
+
): void {
|
|
13
|
+
const defaultProject = config.defaultProject;
|
|
14
|
+
|
|
15
|
+
// --------------------------------------------------------------------------
|
|
16
|
+
// 17. session_start
|
|
17
|
+
// --------------------------------------------------------------------------
|
|
18
|
+
if (isToolEnabled("session_start")) {
|
|
19
|
+
api.registerTool((ctx) => ({
|
|
20
|
+
|
|
21
|
+
name: "session_start",
|
|
22
|
+
description:
|
|
23
|
+
"Start a new work session. Sessions track the lifecycle of a task or conversation for later review. Call this early in your workflow and save the returned session ID for session_end later." +
|
|
24
|
+
(defaultProject ? ` Project defaults to '${defaultProject}' if not specified.` : ""),
|
|
25
|
+
parameters: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
title: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "Session title describing the goal or task.",
|
|
31
|
+
},
|
|
32
|
+
project: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "Project slug to associate this session with.",
|
|
35
|
+
},
|
|
36
|
+
metadata: {
|
|
37
|
+
type: "object",
|
|
38
|
+
description: "Optional key-value metadata.",
|
|
39
|
+
additionalProperties: { type: "string" },
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
execute: async (
|
|
44
|
+
_id,
|
|
45
|
+
args: { title?: string; project?: string; metadata?: Record<string, string> },
|
|
46
|
+
) => {
|
|
47
|
+
try {
|
|
48
|
+
const project = args.project ?? defaultProject;
|
|
49
|
+
const result = await client.startSession(args.title, project, args.metadata);
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
52
|
+
details: { result },
|
|
53
|
+
};
|
|
54
|
+
} catch (err) {
|
|
55
|
+
return {
|
|
56
|
+
content: [{ type: "text", text: `Failed to start session: ${String(err)}` }],
|
|
57
|
+
details: { error: String(err) },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
}),
|
|
62
|
+
{ name: "session_start" },
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// --------------------------------------------------------------------------
|
|
67
|
+
// 18. session_end
|
|
68
|
+
// --------------------------------------------------------------------------
|
|
69
|
+
if (isToolEnabled("session_end")) {
|
|
70
|
+
api.registerTool((ctx) => ({
|
|
71
|
+
|
|
72
|
+
name: "session_end",
|
|
73
|
+
description: "End an active session with a summary of what was accomplished. Always include a meaningful summary — it serves as the historical record of the session.",
|
|
74
|
+
parameters: {
|
|
75
|
+
type: "object",
|
|
76
|
+
properties: {
|
|
77
|
+
id: {
|
|
78
|
+
type: "string",
|
|
79
|
+
description: "Session ID to end.",
|
|
80
|
+
},
|
|
81
|
+
summary: {
|
|
82
|
+
type: "string",
|
|
83
|
+
description: "Summary of what was accomplished during this session.",
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
required: ["id"],
|
|
87
|
+
},
|
|
88
|
+
execute: async (_id, args: { id: string; summary?: string }) => {
|
|
89
|
+
try {
|
|
90
|
+
const result = await client.endSession(args.id, args.summary);
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: "text", text: `Session ${args.id.slice(0, 8)}... ended.` }],
|
|
93
|
+
details: { result },
|
|
94
|
+
};
|
|
95
|
+
} catch (err) {
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: "text", text: `Failed to end session: ${String(err)}` }],
|
|
98
|
+
details: { error: String(err) },
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
{ name: "session_end" },
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// --------------------------------------------------------------------------
|
|
108
|
+
// 19. session_recall
|
|
109
|
+
// --------------------------------------------------------------------------
|
|
110
|
+
if (isToolEnabled("session_recall")) {
|
|
111
|
+
api.registerTool((ctx) => ({
|
|
112
|
+
|
|
113
|
+
name: "session_recall",
|
|
114
|
+
description: "Retrieve details of a specific session including its timeline and associated memories.",
|
|
115
|
+
parameters: {
|
|
116
|
+
type: "object",
|
|
117
|
+
properties: {
|
|
118
|
+
id: {
|
|
119
|
+
type: "string",
|
|
120
|
+
description: "Session ID to retrieve.",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
required: ["id"],
|
|
124
|
+
},
|
|
125
|
+
execute: async (_id, args: { id: string }) => {
|
|
126
|
+
try {
|
|
127
|
+
const result = await client.getSession(args.id);
|
|
128
|
+
return {
|
|
129
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
130
|
+
details: { result },
|
|
131
|
+
};
|
|
132
|
+
} catch (err) {
|
|
133
|
+
return {
|
|
134
|
+
content: [{ type: "text", text: `Failed to recall session: ${String(err)}` }],
|
|
135
|
+
details: { error: String(err) },
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
}),
|
|
140
|
+
{ name: "session_recall" },
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// --------------------------------------------------------------------------
|
|
145
|
+
// 20. session_list
|
|
146
|
+
// --------------------------------------------------------------------------
|
|
147
|
+
if (isToolEnabled("session_list")) {
|
|
148
|
+
api.registerTool((ctx) => ({
|
|
149
|
+
|
|
150
|
+
name: "session_list",
|
|
151
|
+
description: "List sessions, optionally filtered by project or status." +
|
|
152
|
+
(defaultProject ? ` Scoped to project '${defaultProject}' by default.` : ""),
|
|
153
|
+
parameters: {
|
|
154
|
+
type: "object",
|
|
155
|
+
properties: {
|
|
156
|
+
limit: {
|
|
157
|
+
type: "number",
|
|
158
|
+
description: "Maximum sessions to return. Default 20.",
|
|
159
|
+
minimum: 1,
|
|
160
|
+
maximum: 100,
|
|
161
|
+
},
|
|
162
|
+
project: {
|
|
163
|
+
type: "string",
|
|
164
|
+
description: "Filter by project slug.",
|
|
165
|
+
},
|
|
166
|
+
status: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Filter by status (active, ended).",
|
|
169
|
+
enum: ["active", "ended"],
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
execute: async (
|
|
174
|
+
_id,
|
|
175
|
+
args: { limit?: number; project?: string; status?: string },
|
|
176
|
+
) => {
|
|
177
|
+
try {
|
|
178
|
+
const project = args.project ?? defaultProject;
|
|
179
|
+
const result = await client.listSessions(args.limit, project, args.status);
|
|
180
|
+
return {
|
|
181
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
182
|
+
details: { result },
|
|
183
|
+
};
|
|
184
|
+
} catch (err) {
|
|
185
|
+
return {
|
|
186
|
+
content: [{ type: "text", text: `Failed to list sessions: ${String(err)}` }],
|
|
187
|
+
details: { error: String(err) },
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
}),
|
|
192
|
+
{ name: "session_list" },
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
2
|
+
import type { PluginConfig } from "../pipelines/types.js";
|
|
3
|
+
import type { MemoryRelayClient } from "../client/memoryrelay-client.js";
|
|
4
|
+
|
|
5
|
+
export function registerV2Tools(
|
|
6
|
+
api: OpenClawPluginApi,
|
|
7
|
+
config: PluginConfig,
|
|
8
|
+
client: MemoryRelayClient,
|
|
9
|
+
isToolEnabled: (name: string) => boolean,
|
|
10
|
+
): void {
|
|
11
|
+
const defaultProject = config.defaultProject;
|
|
12
|
+
|
|
13
|
+
// --------------------------------------------------------------------------
|
|
14
|
+
// 40. memory_store_async
|
|
15
|
+
// --------------------------------------------------------------------------
|
|
16
|
+
if (isToolEnabled("memory_store_async")) {
|
|
17
|
+
api.registerTool((_ctx) => ({
|
|
18
|
+
name: "memory_store_async",
|
|
19
|
+
description:
|
|
20
|
+
"Store a memory asynchronously using V2 API. Returns immediately (<50ms) with a job ID. Background workers generate the embedding. Use memory_status to poll for completion. Prefer this over memory_store for high-throughput or latency-sensitive applications." +
|
|
21
|
+
(defaultProject ? ` Project defaults to '${defaultProject}' if not specified.` : ""),
|
|
22
|
+
parameters: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
content: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "The memory content to store (1-50,000 characters).",
|
|
28
|
+
},
|
|
29
|
+
metadata: {
|
|
30
|
+
type: "object",
|
|
31
|
+
description: "Optional key-value metadata to attach to the memory.",
|
|
32
|
+
additionalProperties: { type: "string" },
|
|
33
|
+
},
|
|
34
|
+
project: {
|
|
35
|
+
type: "string",
|
|
36
|
+
description: "Project slug to associate with this memory (max 100 characters).",
|
|
37
|
+
maxLength: 100,
|
|
38
|
+
},
|
|
39
|
+
importance: {
|
|
40
|
+
type: "number",
|
|
41
|
+
description: "Importance score (0-1). Higher values are retained longer.",
|
|
42
|
+
minimum: 0,
|
|
43
|
+
maximum: 1,
|
|
44
|
+
},
|
|
45
|
+
tier: {
|
|
46
|
+
type: "string",
|
|
47
|
+
description: "Memory tier: hot, warm, or cold.",
|
|
48
|
+
enum: ["hot", "warm", "cold"],
|
|
49
|
+
},
|
|
50
|
+
webhook_url: {
|
|
51
|
+
type: "string",
|
|
52
|
+
description: "Optional webhook URL to notify when async storage completes.",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
required: ["content"],
|
|
56
|
+
},
|
|
57
|
+
execute: async (
|
|
58
|
+
_id,
|
|
59
|
+
args: {
|
|
60
|
+
content: string;
|
|
61
|
+
metadata?: Record<string, string>;
|
|
62
|
+
project?: string;
|
|
63
|
+
importance?: number;
|
|
64
|
+
tier?: string;
|
|
65
|
+
webhook_url?: string;
|
|
66
|
+
},
|
|
67
|
+
) => {
|
|
68
|
+
try {
|
|
69
|
+
const { content, metadata, importance, tier, webhook_url } = args;
|
|
70
|
+
let project = args.project;
|
|
71
|
+
if (!project && defaultProject) project = defaultProject;
|
|
72
|
+
const result = await client.storeAsync(content, metadata, project, importance, tier, webhook_url);
|
|
73
|
+
return {
|
|
74
|
+
content: [
|
|
75
|
+
{
|
|
76
|
+
type: "text",
|
|
77
|
+
text: `Memory queued for async storage (id: ${result.id}, job_id: ${result.job_id}). Use memory_status to check completion.`,
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
details: result,
|
|
81
|
+
};
|
|
82
|
+
} catch (err) {
|
|
83
|
+
return {
|
|
84
|
+
content: [{ type: "text", text: `Failed to queue memory: ${String(err)}` }],
|
|
85
|
+
details: { error: String(err) },
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
}), { name: "memory_store_async" });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// --------------------------------------------------------------------------
|
|
93
|
+
// 41. memory_status
|
|
94
|
+
// --------------------------------------------------------------------------
|
|
95
|
+
if (isToolEnabled("memory_status")) {
|
|
96
|
+
api.registerTool((_ctx) => ({
|
|
97
|
+
name: "memory_status",
|
|
98
|
+
description:
|
|
99
|
+
"Check the processing status of a memory created via memory_store_async. Status values: pending (waiting for worker), processing (generating embedding), ready (searchable), failed (error occurred).",
|
|
100
|
+
parameters: {
|
|
101
|
+
type: "object",
|
|
102
|
+
properties: {
|
|
103
|
+
memory_id: {
|
|
104
|
+
type: "string",
|
|
105
|
+
description: "The memory ID returned by memory_store_async.",
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
required: ["memory_id"],
|
|
109
|
+
},
|
|
110
|
+
execute: async (
|
|
111
|
+
_id,
|
|
112
|
+
args: { memory_id: string },
|
|
113
|
+
) => {
|
|
114
|
+
try {
|
|
115
|
+
const status = await client.getMemoryStatus(args.memory_id);
|
|
116
|
+
return {
|
|
117
|
+
content: [
|
|
118
|
+
{
|
|
119
|
+
type: "text",
|
|
120
|
+
text: JSON.stringify(status, null, 2),
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
details: status,
|
|
124
|
+
};
|
|
125
|
+
} catch (err) {
|
|
126
|
+
return {
|
|
127
|
+
content: [{ type: "text", text: `Failed to get memory status: ${String(err)}` }],
|
|
128
|
+
details: { error: String(err) },
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
}), { name: "memory_status" });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// --------------------------------------------------------------------------
|
|
136
|
+
// 42. context_build
|
|
137
|
+
// --------------------------------------------------------------------------
|
|
138
|
+
if (isToolEnabled("context_build")) {
|
|
139
|
+
api.registerTool((_ctx) => ({
|
|
140
|
+
name: "context_build",
|
|
141
|
+
description:
|
|
142
|
+
"Build a ranked context bundle from memories with optional AI summarization. Searches for relevant memories, ranks them by composite score, and optionally generates an AI summary. Useful for building token-efficient context windows.",
|
|
143
|
+
parameters: {
|
|
144
|
+
type: "object",
|
|
145
|
+
properties: {
|
|
146
|
+
query: {
|
|
147
|
+
type: "string",
|
|
148
|
+
description: "The query to build context for.",
|
|
149
|
+
},
|
|
150
|
+
max_memories: {
|
|
151
|
+
type: "number",
|
|
152
|
+
description: "Maximum number of memories to include (1-100).",
|
|
153
|
+
minimum: 1,
|
|
154
|
+
maximum: 100,
|
|
155
|
+
},
|
|
156
|
+
max_tokens: {
|
|
157
|
+
type: "number",
|
|
158
|
+
description: "Maximum tokens for the context bundle (100-128000).",
|
|
159
|
+
minimum: 100,
|
|
160
|
+
maximum: 128000,
|
|
161
|
+
},
|
|
162
|
+
ai_enhanced: {
|
|
163
|
+
type: "boolean",
|
|
164
|
+
description: "If true, generate an AI summary of the retrieved memories.",
|
|
165
|
+
},
|
|
166
|
+
search_mode: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Search strategy: semantic, hybrid, or keyword.",
|
|
169
|
+
enum: ["semantic", "hybrid", "keyword"],
|
|
170
|
+
},
|
|
171
|
+
exclude_memory_ids: {
|
|
172
|
+
type: "array",
|
|
173
|
+
description: "Memory IDs to exclude from results.",
|
|
174
|
+
items: { type: "string" },
|
|
175
|
+
},
|
|
176
|
+
llm_api_url: {
|
|
177
|
+
type: "string",
|
|
178
|
+
description: "Optional custom LLM API URL for AI summarization.",
|
|
179
|
+
},
|
|
180
|
+
llm_model: {
|
|
181
|
+
type: "string",
|
|
182
|
+
description: "Optional LLM model name for AI summarization.",
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
required: ["query"],
|
|
186
|
+
},
|
|
187
|
+
execute: async (
|
|
188
|
+
_id,
|
|
189
|
+
args: {
|
|
190
|
+
query: string;
|
|
191
|
+
max_memories?: number;
|
|
192
|
+
max_tokens?: number;
|
|
193
|
+
ai_enhanced?: boolean;
|
|
194
|
+
search_mode?: "semantic" | "hybrid" | "keyword";
|
|
195
|
+
exclude_memory_ids?: string[];
|
|
196
|
+
llm_api_url?: string;
|
|
197
|
+
llm_model?: string;
|
|
198
|
+
},
|
|
199
|
+
) => {
|
|
200
|
+
try {
|
|
201
|
+
const context = await client.buildContextV2(args.query, {
|
|
202
|
+
maxMemories: args.max_memories,
|
|
203
|
+
maxTokens: args.max_tokens,
|
|
204
|
+
aiEnhanced: args.ai_enhanced,
|
|
205
|
+
searchMode: args.search_mode,
|
|
206
|
+
excludeMemoryIds: args.exclude_memory_ids,
|
|
207
|
+
llmApiUrl: args.llm_api_url,
|
|
208
|
+
llmModel: args.llm_model,
|
|
209
|
+
});
|
|
210
|
+
return {
|
|
211
|
+
content: [
|
|
212
|
+
{
|
|
213
|
+
type: "text",
|
|
214
|
+
text: JSON.stringify(context, null, 2),
|
|
215
|
+
},
|
|
216
|
+
],
|
|
217
|
+
details: context,
|
|
218
|
+
};
|
|
219
|
+
} catch (err) {
|
|
220
|
+
return {
|
|
221
|
+
content: [{ type: "text", text: `Failed to build context: ${String(err)}` }],
|
|
222
|
+
details: { error: String(err) },
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
}), { name: "context_build" });
|
|
227
|
+
}
|
|
228
|
+
}
|