@memoryrelay/plugin-memoryrelay-ai 0.14.0 → 0.15.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 +14 -4
- package/index.ts +304 -3
- package/openclaw.plugin.json +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -21,9 +21,10 @@ MemoryRelay is designed for engineering teams managing complex, long-running pro
|
|
|
21
21
|
| Entities / knowledge graph | Yes (create, link, graph) | Yes | No |
|
|
22
22
|
| Multi-agent collaboration | Yes (agent scoping, subagent tracking) | Limited | No |
|
|
23
23
|
| Auto-capture with privacy tiers | Yes (off/conservative/smart/aggressive) | Basic | No |
|
|
24
|
-
|
|
|
24
|
+
| V2 Async Storage | Yes | No | No |
|
|
25
|
+
| Direct commands | 16 | ~5 | 0 |
|
|
25
26
|
| Lifecycle hooks | 13 | 0 | 0 |
|
|
26
|
-
| Tools |
|
|
27
|
+
| Tools | 42 | ~10 | 0 |
|
|
27
28
|
|
|
28
29
|
## Quick Start
|
|
29
30
|
|
|
@@ -75,7 +76,7 @@ Auto-recall and smart auto-capture are enabled by default. The plugin injects re
|
|
|
75
76
|
- Pattern adoption ensures consistent code style across sessions
|
|
76
77
|
- Session tracking provides continuity when context windows reset
|
|
77
78
|
|
|
78
|
-
## Features --
|
|
79
|
+
## Features -- 42 Tools by Category
|
|
79
80
|
|
|
80
81
|
### Memory (9 tools) -- group: `memory`
|
|
81
82
|
|
|
@@ -150,6 +151,14 @@ Auto-recall and smart auto-capture are enabled by default. The plugin injects re
|
|
|
150
151
|
| `project_shared_patterns` | Find patterns shared between two projects |
|
|
151
152
|
| `project_context` | Load full project context (memories, decisions, patterns, sessions) |
|
|
152
153
|
|
|
154
|
+
### V2 Async (3 tools) -- group: `v2`
|
|
155
|
+
|
|
156
|
+
| Tool | Description |
|
|
157
|
+
|------|-------------|
|
|
158
|
+
| `memory_store_async` | Store a memory asynchronously and return a job ID |
|
|
159
|
+
| `memory_status` | Check the processing status of an async memory job |
|
|
160
|
+
| `context_build` | Build a ranked context bundle from relevant memories |
|
|
161
|
+
|
|
153
162
|
### Health (1 tool) -- group: `health`
|
|
154
163
|
|
|
155
164
|
| Tool | Description |
|
|
@@ -165,6 +174,7 @@ These slash commands bypass the LLM and execute immediately.
|
|
|
165
174
|
| Command | Description |
|
|
166
175
|
|---------|-------------|
|
|
167
176
|
| `/memory-search <query>` | Semantic search across stored memories |
|
|
177
|
+
| `/memory-context` | Build ranked context bundle from memories |
|
|
168
178
|
| `/memory-sessions` | List sessions (optional: `active`, `closed`, or project slug) |
|
|
169
179
|
| `/memory-decisions` | List architectural decisions (optional: project slug) |
|
|
170
180
|
| `/memory-patterns` | List or search patterns (optional: search query) |
|
|
@@ -304,7 +314,7 @@ The plugin registers 14 lifecycle hooks:
|
|
|
304
314
|
|
|
305
315
|
### Skills
|
|
306
316
|
|
|
307
|
-
The plugin ships with
|
|
317
|
+
The plugin ships with 9 skills providing guided workflows on top of the raw tools:
|
|
308
318
|
|
|
309
319
|
- **Agent-facing**: `memory-workflow`, `decision-tracking`, `pattern-management`, `project-orchestration`, `entity-and-context`
|
|
310
320
|
- **Developer-facing**: `codebase-navigation`, `testing-memoryrelay`, `release-process`
|
package/index.ts
CHANGED
|
@@ -709,7 +709,7 @@ class MemoryRelayClient {
|
|
|
709
709
|
headers: {
|
|
710
710
|
"Content-Type": "application/json",
|
|
711
711
|
Authorization: `Bearer ${this.apiKey}`,
|
|
712
|
-
"User-Agent": "openclaw-memory-memoryrelay/0.
|
|
712
|
+
"User-Agent": "openclaw-memory-memoryrelay/0.15.0",
|
|
713
713
|
},
|
|
714
714
|
body: body ? JSON.stringify(body) : undefined,
|
|
715
715
|
},
|
|
@@ -936,6 +936,63 @@ class MemoryRelayClient {
|
|
|
936
936
|
});
|
|
937
937
|
}
|
|
938
938
|
|
|
939
|
+
// --------------------------------------------------------------------------
|
|
940
|
+
// V2 Async API Methods (v0.15.0)
|
|
941
|
+
// --------------------------------------------------------------------------
|
|
942
|
+
|
|
943
|
+
async storeAsync(
|
|
944
|
+
content: string,
|
|
945
|
+
metadata?: Record<string, string>,
|
|
946
|
+
project?: string,
|
|
947
|
+
importance?: number,
|
|
948
|
+
tier?: string,
|
|
949
|
+
): Promise<{ id: string; status: string; job_id: string; estimated_completion_seconds: number }> {
|
|
950
|
+
if (!content || content.length === 0 || content.length > 50000) {
|
|
951
|
+
throw new Error("Content must be between 1 and 50,000 characters");
|
|
952
|
+
}
|
|
953
|
+
const body: Record<string, unknown> = {
|
|
954
|
+
content,
|
|
955
|
+
agent_id: this.agentId,
|
|
956
|
+
};
|
|
957
|
+
if (metadata) body.metadata = metadata;
|
|
958
|
+
if (project) body.project = project;
|
|
959
|
+
if (importance != null) body.importance = importance;
|
|
960
|
+
if (tier) body.tier = tier;
|
|
961
|
+
return this.request("POST", "/v2/memories", body);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
async getMemoryStatus(memoryId: string): Promise<{
|
|
965
|
+
id: string;
|
|
966
|
+
status: "pending" | "processing" | "ready" | "failed";
|
|
967
|
+
created_at: string;
|
|
968
|
+
updated_at: string;
|
|
969
|
+
error?: string;
|
|
970
|
+
}> {
|
|
971
|
+
return this.request("GET", `/v2/memories/${memoryId}/status`);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
async buildContextV2(
|
|
975
|
+
query: string,
|
|
976
|
+
options?: {
|
|
977
|
+
maxMemories?: number;
|
|
978
|
+
maxTokens?: number;
|
|
979
|
+
aiEnhanced?: boolean;
|
|
980
|
+
searchMode?: "semantic" | "hybrid" | "keyword";
|
|
981
|
+
excludeMemoryIds?: string[];
|
|
982
|
+
},
|
|
983
|
+
): Promise<any> {
|
|
984
|
+
const body: Record<string, unknown> = {
|
|
985
|
+
query,
|
|
986
|
+
agent_id: this.agentId,
|
|
987
|
+
};
|
|
988
|
+
if (options?.maxMemories != null) body.max_memories = options.maxMemories;
|
|
989
|
+
if (options?.maxTokens != null) body.max_tokens = options.maxTokens;
|
|
990
|
+
if (options?.aiEnhanced != null) body.ai_enhanced = options.aiEnhanced;
|
|
991
|
+
if (options?.searchMode) body.search_mode = options.searchMode;
|
|
992
|
+
if (options?.excludeMemoryIds) body.exclude_memory_ids = options.excludeMemoryIds;
|
|
993
|
+
return this.request("POST", "/v2/context", body);
|
|
994
|
+
}
|
|
995
|
+
|
|
939
996
|
// --------------------------------------------------------------------------
|
|
940
997
|
// Entity operations
|
|
941
998
|
// --------------------------------------------------------------------------
|
|
@@ -1583,6 +1640,7 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
|
|
|
1583
1640
|
"project_related", "project_impact", "project_shared_patterns", "project_context",
|
|
1584
1641
|
],
|
|
1585
1642
|
health: ["memory_health"],
|
|
1643
|
+
v2: ["memory_store_async", "memory_status", "context_build"],
|
|
1586
1644
|
};
|
|
1587
1645
|
|
|
1588
1646
|
// Build a set of enabled tool names from group names
|
|
@@ -3746,6 +3804,202 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
|
|
|
3746
3804
|
);
|
|
3747
3805
|
}
|
|
3748
3806
|
|
|
3807
|
+
// 40. memory_store_async
|
|
3808
|
+
// --------------------------------------------------------------------------
|
|
3809
|
+
if (isToolEnabled("memory_store_async")) {
|
|
3810
|
+
api.registerTool((_ctx) => ({
|
|
3811
|
+
name: "memory_store_async",
|
|
3812
|
+
description:
|
|
3813
|
+
"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." +
|
|
3814
|
+
(defaultProject ? ` Project defaults to '${defaultProject}' if not specified.` : ""),
|
|
3815
|
+
parameters: {
|
|
3816
|
+
type: "object",
|
|
3817
|
+
properties: {
|
|
3818
|
+
content: {
|
|
3819
|
+
type: "string",
|
|
3820
|
+
description: "The memory content to store (1–50,000 characters).",
|
|
3821
|
+
},
|
|
3822
|
+
metadata: {
|
|
3823
|
+
type: "object",
|
|
3824
|
+
description: "Optional key-value metadata to attach to the memory.",
|
|
3825
|
+
additionalProperties: { type: "string" },
|
|
3826
|
+
},
|
|
3827
|
+
project: {
|
|
3828
|
+
type: "string",
|
|
3829
|
+
description: "Project slug to associate with this memory (max 100 characters).",
|
|
3830
|
+
maxLength: 100,
|
|
3831
|
+
},
|
|
3832
|
+
importance: {
|
|
3833
|
+
type: "number",
|
|
3834
|
+
description: "Importance score (0-1). Higher values are retained longer.",
|
|
3835
|
+
minimum: 0,
|
|
3836
|
+
maximum: 1,
|
|
3837
|
+
},
|
|
3838
|
+
tier: {
|
|
3839
|
+
type: "string",
|
|
3840
|
+
description: "Memory tier: hot, warm, or cold.",
|
|
3841
|
+
enum: ["hot", "warm", "cold"],
|
|
3842
|
+
},
|
|
3843
|
+
},
|
|
3844
|
+
required: ["content"],
|
|
3845
|
+
},
|
|
3846
|
+
execute: async (
|
|
3847
|
+
_id,
|
|
3848
|
+
args: {
|
|
3849
|
+
content: string;
|
|
3850
|
+
metadata?: Record<string, string>;
|
|
3851
|
+
project?: string;
|
|
3852
|
+
importance?: number;
|
|
3853
|
+
tier?: string;
|
|
3854
|
+
},
|
|
3855
|
+
) => {
|
|
3856
|
+
try {
|
|
3857
|
+
const { content, metadata, importance, tier } = args;
|
|
3858
|
+
let project = args.project;
|
|
3859
|
+
if (!project && defaultProject) project = defaultProject;
|
|
3860
|
+
const result = await client.storeAsync(content, metadata, project, importance, tier);
|
|
3861
|
+
return {
|
|
3862
|
+
content: [
|
|
3863
|
+
{
|
|
3864
|
+
type: "text",
|
|
3865
|
+
text: `Memory queued for async storage (id: ${result.id}, job_id: ${result.job_id}). Use memory_status to check completion.`,
|
|
3866
|
+
},
|
|
3867
|
+
],
|
|
3868
|
+
details: result,
|
|
3869
|
+
};
|
|
3870
|
+
} catch (err) {
|
|
3871
|
+
return {
|
|
3872
|
+
content: [{ type: "text", text: `Failed to queue memory: ${String(err)}` }],
|
|
3873
|
+
details: { error: String(err) },
|
|
3874
|
+
};
|
|
3875
|
+
}
|
|
3876
|
+
},
|
|
3877
|
+
}), { name: "memory_store_async" });
|
|
3878
|
+
}
|
|
3879
|
+
|
|
3880
|
+
// 41. memory_status
|
|
3881
|
+
// --------------------------------------------------------------------------
|
|
3882
|
+
if (isToolEnabled("memory_status")) {
|
|
3883
|
+
api.registerTool((_ctx) => ({
|
|
3884
|
+
name: "memory_status",
|
|
3885
|
+
description:
|
|
3886
|
+
"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).",
|
|
3887
|
+
parameters: {
|
|
3888
|
+
type: "object",
|
|
3889
|
+
properties: {
|
|
3890
|
+
memory_id: {
|
|
3891
|
+
type: "string",
|
|
3892
|
+
description: "The memory ID returned by memory_store_async.",
|
|
3893
|
+
},
|
|
3894
|
+
},
|
|
3895
|
+
required: ["memory_id"],
|
|
3896
|
+
},
|
|
3897
|
+
execute: async (
|
|
3898
|
+
_id,
|
|
3899
|
+
args: { memory_id: string },
|
|
3900
|
+
) => {
|
|
3901
|
+
try {
|
|
3902
|
+
const status = await client.getMemoryStatus(args.memory_id);
|
|
3903
|
+
return {
|
|
3904
|
+
content: [
|
|
3905
|
+
{
|
|
3906
|
+
type: "text",
|
|
3907
|
+
text: JSON.stringify(status, null, 2),
|
|
3908
|
+
},
|
|
3909
|
+
],
|
|
3910
|
+
details: status,
|
|
3911
|
+
};
|
|
3912
|
+
} catch (err) {
|
|
3913
|
+
return {
|
|
3914
|
+
content: [{ type: "text", text: `Failed to get memory status: ${String(err)}` }],
|
|
3915
|
+
details: { error: String(err) },
|
|
3916
|
+
};
|
|
3917
|
+
}
|
|
3918
|
+
},
|
|
3919
|
+
}), { name: "memory_status" });
|
|
3920
|
+
}
|
|
3921
|
+
|
|
3922
|
+
// 42. context_build
|
|
3923
|
+
// --------------------------------------------------------------------------
|
|
3924
|
+
if (isToolEnabled("context_build")) {
|
|
3925
|
+
api.registerTool((_ctx) => ({
|
|
3926
|
+
name: "context_build",
|
|
3927
|
+
description:
|
|
3928
|
+
"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.",
|
|
3929
|
+
parameters: {
|
|
3930
|
+
type: "object",
|
|
3931
|
+
properties: {
|
|
3932
|
+
query: {
|
|
3933
|
+
type: "string",
|
|
3934
|
+
description: "The query to build context for.",
|
|
3935
|
+
},
|
|
3936
|
+
max_memories: {
|
|
3937
|
+
type: "number",
|
|
3938
|
+
description: "Maximum number of memories to include (1-100).",
|
|
3939
|
+
minimum: 1,
|
|
3940
|
+
maximum: 100,
|
|
3941
|
+
},
|
|
3942
|
+
max_tokens: {
|
|
3943
|
+
type: "number",
|
|
3944
|
+
description: "Maximum tokens for the context bundle (100-128000).",
|
|
3945
|
+
minimum: 100,
|
|
3946
|
+
maximum: 128000,
|
|
3947
|
+
},
|
|
3948
|
+
ai_enhanced: {
|
|
3949
|
+
type: "boolean",
|
|
3950
|
+
description: "If true, generate an AI summary of the retrieved memories.",
|
|
3951
|
+
},
|
|
3952
|
+
search_mode: {
|
|
3953
|
+
type: "string",
|
|
3954
|
+
description: "Search strategy: semantic, hybrid, or keyword.",
|
|
3955
|
+
enum: ["semantic", "hybrid", "keyword"],
|
|
3956
|
+
},
|
|
3957
|
+
exclude_memory_ids: {
|
|
3958
|
+
type: "array",
|
|
3959
|
+
description: "Memory IDs to exclude from results.",
|
|
3960
|
+
items: { type: "string" },
|
|
3961
|
+
},
|
|
3962
|
+
},
|
|
3963
|
+
required: ["query"],
|
|
3964
|
+
},
|
|
3965
|
+
execute: async (
|
|
3966
|
+
_id,
|
|
3967
|
+
args: {
|
|
3968
|
+
query: string;
|
|
3969
|
+
max_memories?: number;
|
|
3970
|
+
max_tokens?: number;
|
|
3971
|
+
ai_enhanced?: boolean;
|
|
3972
|
+
search_mode?: "semantic" | "hybrid" | "keyword";
|
|
3973
|
+
exclude_memory_ids?: string[];
|
|
3974
|
+
},
|
|
3975
|
+
) => {
|
|
3976
|
+
try {
|
|
3977
|
+
const context = await client.buildContextV2(args.query, {
|
|
3978
|
+
maxMemories: args.max_memories,
|
|
3979
|
+
maxTokens: args.max_tokens,
|
|
3980
|
+
aiEnhanced: args.ai_enhanced,
|
|
3981
|
+
searchMode: args.search_mode,
|
|
3982
|
+
excludeMemoryIds: args.exclude_memory_ids,
|
|
3983
|
+
});
|
|
3984
|
+
return {
|
|
3985
|
+
content: [
|
|
3986
|
+
{
|
|
3987
|
+
type: "text",
|
|
3988
|
+
text: JSON.stringify(context, null, 2),
|
|
3989
|
+
},
|
|
3990
|
+
],
|
|
3991
|
+
details: context,
|
|
3992
|
+
};
|
|
3993
|
+
} catch (err) {
|
|
3994
|
+
return {
|
|
3995
|
+
content: [{ type: "text", text: `Failed to build context: ${String(err)}` }],
|
|
3996
|
+
details: { error: String(err) },
|
|
3997
|
+
};
|
|
3998
|
+
}
|
|
3999
|
+
},
|
|
4000
|
+
}), { name: "context_build" });
|
|
4001
|
+
}
|
|
4002
|
+
|
|
3749
4003
|
// ========================================================================
|
|
3750
4004
|
// CLI Commands
|
|
3751
4005
|
// ========================================================================
|
|
@@ -4236,7 +4490,7 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
|
|
|
4236
4490
|
});
|
|
4237
4491
|
|
|
4238
4492
|
api.logger.info?.(
|
|
4239
|
-
`memory-memoryrelay: plugin v0.
|
|
4493
|
+
`memory-memoryrelay: plugin v0.15.0 loaded (${Object.values(TOOL_GROUPS).flat().length} tools, autoRecall: ${cfg?.autoRecall}, autoCapture: ${autoCaptureConfig.enabled ? autoCaptureConfig.tier : 'off'}, debug: ${debugEnabled})`,
|
|
4240
4494
|
);
|
|
4241
4495
|
|
|
4242
4496
|
// ========================================================================
|
|
@@ -4644,7 +4898,7 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
|
|
|
4644
4898
|
}
|
|
4645
4899
|
|
|
4646
4900
|
// ========================================================================
|
|
4647
|
-
// Direct Commands (
|
|
4901
|
+
// Direct Commands (16 total) — bypass LLM, execute immediately
|
|
4648
4902
|
// ========================================================================
|
|
4649
4903
|
|
|
4650
4904
|
// /memory-status — Show full plugin status report
|
|
@@ -5279,6 +5533,53 @@ export default async function plugin(api: OpenClawPluginApi): Promise<void> {
|
|
|
5279
5533
|
},
|
|
5280
5534
|
});
|
|
5281
5535
|
|
|
5536
|
+
// /memory-context — Build a context bundle from memories using V2 API
|
|
5537
|
+
api.registerCommand?.({
|
|
5538
|
+
name: "memory-context",
|
|
5539
|
+
description: "Build a ranked context bundle from memories for a given query",
|
|
5540
|
+
requireAuth: true,
|
|
5541
|
+
acceptsArgs: true,
|
|
5542
|
+
handler: async (ctx) => {
|
|
5543
|
+
const { positional, flags } = parseCommandArgs(ctx.args);
|
|
5544
|
+
const query = positional.join(" ").trim();
|
|
5545
|
+
if (!query) {
|
|
5546
|
+
return {
|
|
5547
|
+
text: [
|
|
5548
|
+
"Usage: /memory-context <query> [options]",
|
|
5549
|
+
"",
|
|
5550
|
+
"Options:",
|
|
5551
|
+
" --max-memories <n> Maximum memories to include (1-100)",
|
|
5552
|
+
" --max-tokens <n> Maximum tokens for context (100-128000)",
|
|
5553
|
+
" --ai-enhanced Generate an AI summary of memories",
|
|
5554
|
+
" --search-mode <mode> Search strategy: semantic, hybrid, keyword",
|
|
5555
|
+
].join("\n"),
|
|
5556
|
+
};
|
|
5557
|
+
}
|
|
5558
|
+
try {
|
|
5559
|
+
const options: {
|
|
5560
|
+
maxMemories?: number;
|
|
5561
|
+
maxTokens?: number;
|
|
5562
|
+
aiEnhanced?: boolean;
|
|
5563
|
+
searchMode?: "semantic" | "hybrid" | "keyword";
|
|
5564
|
+
} = {};
|
|
5565
|
+
if (flags["max-memories"]) options.maxMemories = parseInt(String(flags["max-memories"]), 10);
|
|
5566
|
+
if (flags["max-tokens"]) options.maxTokens = parseInt(String(flags["max-tokens"]), 10);
|
|
5567
|
+
if (flags["ai-enhanced"] === true) options.aiEnhanced = true;
|
|
5568
|
+
if (flags["search-mode"]) options.searchMode = String(flags["search-mode"]) as "semantic" | "hybrid" | "keyword";
|
|
5569
|
+
|
|
5570
|
+
const context = await client.buildContextV2(query, options);
|
|
5571
|
+
|
|
5572
|
+
if (!context || (Array.isArray(context.memories) && context.memories.length === 0)) {
|
|
5573
|
+
return { text: `No memories found for query: "${query}"` };
|
|
5574
|
+
}
|
|
5575
|
+
|
|
5576
|
+
return { text: JSON.stringify(context, null, 2) };
|
|
5577
|
+
} catch (err) {
|
|
5578
|
+
return { text: `Error: ${String(err)}`, isError: true };
|
|
5579
|
+
}
|
|
5580
|
+
},
|
|
5581
|
+
});
|
|
5582
|
+
|
|
5282
5583
|
// ========================================================================
|
|
5283
5584
|
// Stale Session Cleanup Service (v0.13.0)
|
|
5284
5585
|
// ========================================================================
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"id": "plugin-memoryrelay-ai",
|
|
3
3
|
"kind": "memory",
|
|
4
4
|
"name": "MemoryRelay AI",
|
|
5
|
-
"description": "MemoryRelay v0.
|
|
6
|
-
"version": "0.
|
|
5
|
+
"description": "MemoryRelay v0.15.0 - Long-term memory with 42 tools, 16 commands, V2 async, sessions, decisions, patterns & projects (api.memoryrelay.net)",
|
|
6
|
+
"version": "0.15.0",
|
|
7
7
|
"uiHints": {
|
|
8
8
|
"apiKey": {
|
|
9
9
|
"label": "MemoryRelay API Key",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memoryrelay/plugin-memoryrelay-ai",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "OpenClaw memory plugin for MemoryRelay API -
|
|
3
|
+
"version": "0.15.0",
|
|
4
|
+
"description": "OpenClaw memory plugin for MemoryRelay API - 42 tools, 16 commands, V2 async, sessions, decisions, patterns, projects & semantic search",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
7
7
|
"scripts": {
|