@memoryrelay/plugin-memoryrelay-ai 0.9.4 → 0.9.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/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * OpenClaw Memory Plugin - MemoryRelay (Single File Version)
3
- * Version: 0.9.4
3
+ * Version: 0.9.6
4
4
  */
5
5
 
6
6
  import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
@@ -3,7 +3,7 @@
3
3
  "kind": "memory",
4
4
  "name": "MemoryRelay AI",
5
5
  "description": "AI memory service with sessions, decisions, patterns & projects (api.memoryrelay.net)",
6
- "version": "0.9.4",
6
+ "version": "0.9.6",
7
7
  "uiHints": {
8
8
  "apiKey": {
9
9
  "label": "MemoryRelay API Key",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memoryrelay/plugin-memoryrelay-ai",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "OpenClaw memory plugin for MemoryRelay API - sessions, decisions, patterns, projects & semantic search",
5
5
  "type": "module",
6
6
  "main": "index.ts",
@@ -39,13 +39,11 @@
39
39
  "openclaw": {
40
40
  "id": "plugin-memoryrelay-ai",
41
41
  "extensions": [
42
- "./index.ts"
42
+ "index.ts"
43
43
  ]
44
44
  },
45
45
  "files": [
46
46
  "index.ts",
47
- "src/*.ts",
48
- "!src/*.test.ts",
49
47
  "openclaw.plugin.json",
50
48
  "README.md",
51
49
  "LICENSE"
@@ -1,169 +0,0 @@
1
- /**
2
- * Debug Logger for MemoryRelay OpenClaw Plugin
3
- *
4
- * Provides comprehensive logging of API calls with request/response capture
5
- * for troubleshooting and performance analysis.
6
- *
7
- * Note: File logging has been removed in v0.8.4 to pass OpenClaw security validation.
8
- * All logs are kept in-memory only. Use gateway methods (coming in v0.9.0) to access logs.
9
- */
10
-
11
- export interface LogEntry {
12
- timestamp: string;
13
- tool: string;
14
- method: string;
15
- path: string;
16
- duration: number;
17
- status: "success" | "error";
18
- requestBody?: unknown;
19
- responseBody?: unknown;
20
- responseStatus?: number;
21
- error?: string;
22
- retries?: number;
23
- }
24
-
25
- export interface DebugLoggerConfig {
26
- enabled: boolean;
27
- verbose: boolean;
28
- maxEntries: number;
29
- logFile?: string; // Deprecated: File logging removed for security compliance
30
- }
31
-
32
- export class DebugLogger {
33
- private logs: LogEntry[] = [];
34
- private config: DebugLoggerConfig;
35
-
36
- constructor(config: DebugLoggerConfig) {
37
- this.config = config;
38
-
39
- // logFile is no longer supported (v0.8.4)
40
- if (config.logFile) {
41
- console.warn(
42
- "memoryrelay: logFile is deprecated and ignored. " +
43
- "Use gateway methods to access debug logs (coming in v0.9.0)"
44
- );
45
- }
46
- }
47
-
48
- /**
49
- * Log an API call
50
- */
51
- log(entry: LogEntry): void {
52
- if (!this.config.enabled) return;
53
-
54
- // Add to in-memory buffer
55
- this.logs.push(entry);
56
-
57
- // Trim if exceeds max
58
- if (this.logs.length > this.config.maxEntries) {
59
- this.logs.shift();
60
- }
61
- }
62
-
63
- /**
64
- * Get recent logs
65
- */
66
- getRecentLogs(limit: number = 10): LogEntry[] {
67
- return this.logs.slice(-limit);
68
- }
69
-
70
- /**
71
- * Get logs for specific tool
72
- */
73
- getToolLogs(toolName: string, limit: number = 10): LogEntry[] {
74
- return this.logs
75
- .filter(log => log.tool === toolName)
76
- .slice(-limit);
77
- }
78
-
79
- /**
80
- * Get error logs only
81
- */
82
- getErrorLogs(limit: number = 10): LogEntry[] {
83
- return this.logs
84
- .filter(log => log.status === "error")
85
- .slice(-limit);
86
- }
87
-
88
- /**
89
- * Get all logs
90
- */
91
- getAllLogs(): LogEntry[] {
92
- return [...this.logs];
93
- }
94
-
95
- /**
96
- * Clear logs
97
- */
98
- clear(): void {
99
- this.logs = [];
100
- }
101
-
102
- /**
103
- * Get statistics
104
- */
105
- getStats() {
106
- const total = this.logs.length;
107
- const successful = this.logs.filter(l => l.status === "success").length;
108
- const failed = total - successful;
109
- const avgDuration = total > 0
110
- ? this.logs.reduce((sum, l) => sum + l.duration, 0) / total
111
- : 0;
112
-
113
- return {
114
- total,
115
- successful,
116
- failed,
117
- successRate: total > 0 ? (successful / total) * 100 : 0,
118
- avgDuration: Math.round(avgDuration),
119
- };
120
- }
121
-
122
- /**
123
- * Format log entry for display
124
- */
125
- static formatEntry(entry: LogEntry): string {
126
- const timestamp = new Date(entry.timestamp).toLocaleTimeString();
127
- const status = entry.status === "success" ? "✓" : "✗";
128
- const duration = `${entry.duration}ms`;
129
-
130
- let output = `${timestamp} ${entry.tool.padEnd(20)} ${duration.padStart(6)} ${status}`;
131
-
132
- if (entry.error) {
133
- output += `\n Error: ${entry.error}`;
134
- }
135
-
136
- if (entry.retries && entry.retries > 0) {
137
- output += ` (${entry.retries} retries)`;
138
- }
139
-
140
- return output;
141
- }
142
-
143
- /**
144
- * Format logs as table
145
- */
146
- static formatTable(logs: LogEntry[]): string {
147
- if (logs.length === 0) {
148
- return "No logs available";
149
- }
150
-
151
- const lines = [
152
- "TIMESTAMP TOOL DURATION STATUS ERROR",
153
- "━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━ ━━━━━━ ━━━━━━━━━━━━━━━━━━━━━━━━━",
154
- ];
155
-
156
- for (const entry of logs) {
157
- const timestamp = new Date(entry.timestamp).toLocaleTimeString();
158
- const status = entry.status === "success" ? "✓" : "✗";
159
- const duration = `${entry.duration}ms`;
160
- const error = entry.error ? entry.error.substring(0, 30) : "";
161
-
162
- lines.push(
163
- `${timestamp} ${entry.tool.padEnd(20)} ${duration.padStart(8)} ${status.padEnd(6)} ${error}`
164
- );
165
- }
166
-
167
- return lines.join("\n");
168
- }
169
- }
@@ -1,284 +0,0 @@
1
- /**
2
- * Status Reporter for MemoryRelay OpenClaw Plugin
3
- *
4
- * Provides comprehensive status reporting for openclaw status command
5
- * including connection status, tool breakdown, and recent activity.
6
- */
7
-
8
- import type { LogEntry, DebugLogger } from "./debug-logger";
9
-
10
- export interface ToolStatus {
11
- enabled: number;
12
- available: number;
13
- failed: number;
14
- tools: {
15
- name: string;
16
- status: "working" | "error" | "unknown";
17
- error?: string;
18
- lastSuccess?: string;
19
- lastError?: string;
20
- }[];
21
- }
22
-
23
- export interface ConnectionStatus {
24
- status: "connected" | "disconnected" | "degraded";
25
- endpoint: string;
26
- lastCheck: string;
27
- responseTime: number;
28
- }
29
-
30
- export interface MemoryStats {
31
- total_memories: number;
32
- memories_today?: number;
33
- last_stored?: string;
34
- search_count_24h?: number;
35
- }
36
-
37
- export interface PluginConfig {
38
- agentId: string;
39
- autoRecall: boolean;
40
- autoCapture: boolean;
41
- recallLimit: number;
42
- recallThreshold: number;
43
- excludeChannels: string[];
44
- defaultProject?: string;
45
- }
46
-
47
- export interface StatusReport {
48
- connection: ConnectionStatus;
49
- config: PluginConfig;
50
- stats: MemoryStats;
51
- tools: Record<string, ToolStatus>;
52
- recentCalls: LogEntry[];
53
- issues: { tool: string; error: string; since: string }[];
54
- }
55
-
56
- export class StatusReporter {
57
- private debugLogger?: DebugLogger;
58
- private toolFailures: Map<string, { error: string; since: string }> = new Map();
59
-
60
- constructor(debugLogger?: DebugLogger) {
61
- this.debugLogger = debugLogger;
62
- }
63
-
64
- /**
65
- * Record tool failure
66
- */
67
- recordFailure(toolName: string, error: string): void {
68
- if (!this.toolFailures.has(toolName)) {
69
- this.toolFailures.set(toolName, {
70
- error,
71
- since: new Date().toISOString(),
72
- });
73
- }
74
- }
75
-
76
- /**
77
- * Record tool success (clears failure)
78
- */
79
- recordSuccess(toolName: string): void {
80
- this.toolFailures.delete(toolName);
81
- }
82
-
83
- /**
84
- * Get known issues
85
- */
86
- getIssues(): { tool: string; error: string; since: string }[] {
87
- return Array.from(this.toolFailures.entries()).map(([tool, data]) => ({
88
- tool,
89
- error: data.error,
90
- since: data.since,
91
- }));
92
- }
93
-
94
- /**
95
- * Build status report
96
- */
97
- buildReport(
98
- connection: ConnectionStatus,
99
- config: PluginConfig,
100
- stats: MemoryStats,
101
- toolGroups: Record<string, string[]>
102
- ): StatusReport {
103
- const recentCalls = this.debugLogger
104
- ? this.debugLogger.getRecentLogs(10)
105
- : [];
106
-
107
- const tools: Record<string, ToolStatus> = {};
108
-
109
- for (const [group, toolNames] of Object.entries(toolGroups)) {
110
- const toolStatuses = toolNames.map(name => {
111
- const logs = this.debugLogger?.getToolLogs(name, 1) || [];
112
- const lastLog = logs[0];
113
- const failure = this.toolFailures.get(name);
114
-
115
- let status: "working" | "error" | "unknown" = "unknown";
116
- let error: string | undefined;
117
- let lastSuccess: string | undefined;
118
- let lastError: string | undefined;
119
-
120
- if (lastLog) {
121
- status = lastLog.status === "success" ? "working" : "error";
122
- if (lastLog.status === "success") {
123
- lastSuccess = lastLog.timestamp;
124
- } else {
125
- lastError = lastLog.timestamp;
126
- error = lastLog.error;
127
- }
128
- } else if (failure) {
129
- status = "error";
130
- error = failure.error;
131
- lastError = failure.since;
132
- }
133
-
134
- return {
135
- name,
136
- status,
137
- error,
138
- lastSuccess,
139
- lastError,
140
- };
141
- });
142
-
143
- const available = toolStatuses.filter(t => t.status === "working").length;
144
- const failed = toolStatuses.filter(t => t.status === "error").length;
145
-
146
- tools[group] = {
147
- enabled: toolNames.length,
148
- available,
149
- failed,
150
- tools: toolStatuses,
151
- };
152
- }
153
-
154
- return {
155
- connection,
156
- config,
157
- stats,
158
- tools,
159
- recentCalls,
160
- issues: this.getIssues(),
161
- };
162
- }
163
-
164
- /**
165
- * Format status report for CLI display
166
- */
167
- static formatReport(report: StatusReport): string {
168
- const lines: string[] = [];
169
-
170
- // Header
171
- lines.push("");
172
- lines.push("MemoryRelay Plugin Status");
173
- lines.push("━".repeat(50));
174
- lines.push("");
175
-
176
- // Connection
177
- lines.push("CONNECTION");
178
- const connSymbol = report.connection.status === "connected" ? "✓" : "✗";
179
- lines.push(` Status: ${connSymbol} ${report.connection.status}`);
180
- lines.push(` Endpoint: ${report.connection.endpoint}`);
181
- lines.push(` Response Time: ${report.connection.responseTime}ms`);
182
- lines.push(` Last Check: ${new Date(report.connection.lastCheck).toLocaleString()}`);
183
- lines.push("");
184
-
185
- // Configuration
186
- lines.push("CONFIGURATION");
187
- lines.push(` Agent ID: ${report.config.agentId}`);
188
- const recallStatus = report.config.autoRecall
189
- ? `✓ Enabled (limit: ${report.config.recallLimit}, threshold: ${report.config.recallThreshold})`
190
- : "✗ Disabled";
191
- lines.push(` Auto-Recall: ${recallStatus}`);
192
- lines.push(` Auto-Capture: ${report.config.autoCapture ? "✓ Enabled" : "✗ Disabled"}`);
193
- if (report.config.defaultProject) {
194
- lines.push(` Default Project: ${report.config.defaultProject}`);
195
- }
196
- lines.push("");
197
-
198
- // Memory Statistics
199
- lines.push("MEMORY STATISTICS");
200
- lines.push(` Total Memories: ${report.stats.total_memories}`);
201
- if (report.stats.memories_today !== undefined) {
202
- lines.push(` Today: ${report.stats.memories_today}`);
203
- }
204
- if (report.stats.last_stored) {
205
- const lastStored = new Date(report.stats.last_stored);
206
- const ago = this.formatTimeAgo(lastStored);
207
- lines.push(` Last Stored: ${ago}`);
208
- }
209
- if (report.stats.search_count_24h !== undefined) {
210
- lines.push(` Searches (24h): ${report.stats.search_count_24h}`);
211
- }
212
- lines.push("");
213
-
214
- // Tools Status
215
- const totalEnabled = Object.values(report.tools).reduce((sum, g) => sum + g.enabled, 0);
216
- const totalAvailable = Object.values(report.tools).reduce((sum, g) => sum + g.available, 0);
217
- lines.push(`TOOLS STATUS (${totalAvailable}/${totalEnabled} working)`);
218
-
219
- for (const [groupName, group] of Object.entries(report.tools)) {
220
- const symbol = group.failed === 0 ? "✓" : group.failed === group.enabled ? "✗" : "⚠";
221
- const label = groupName.charAt(0).toUpperCase() + groupName.slice(1);
222
- lines.push(` ${symbol} ${label}: ${group.available}/${group.enabled} working`);
223
-
224
- // Show failed tools
225
- const failedTools = group.tools.filter(t => t.status === "error");
226
- for (const tool of failedTools) {
227
- lines.push(` ✗ ${tool.name} (${tool.error})`);
228
- }
229
- }
230
- lines.push("");
231
-
232
- // Recent Activity
233
- if (report.recentCalls.length > 0) {
234
- lines.push(`RECENT ACTIVITY (last ${report.recentCalls.length} calls)`);
235
- for (const call of report.recentCalls.reverse()) {
236
- const time = new Date(call.timestamp).toLocaleTimeString();
237
- const status = call.status === "success" ? "✓" : "✗";
238
- const duration = `${call.duration}ms`;
239
- lines.push(` ${time} ${call.tool.padEnd(18)} ${duration.padStart(6)} ${status}`);
240
- }
241
- lines.push("");
242
- }
243
-
244
- // Known Issues
245
- if (report.issues.length > 0) {
246
- lines.push(`KNOWN ISSUES (${report.issues.length})`);
247
- for (const issue of report.issues) {
248
- const since = this.formatTimeAgo(new Date(issue.since));
249
- lines.push(` ⚠ ${issue.tool} - ${issue.error} (since ${since})`);
250
- }
251
- lines.push("");
252
- }
253
-
254
- // Footer
255
- lines.push("For detailed logs, run: openclaw memoryrelay logs");
256
- lines.push("For troubleshooting: https://github.com/MemoryRelay/api/issues/213");
257
- lines.push("");
258
-
259
- return lines.join("\n");
260
- }
261
-
262
- /**
263
- * Format time ago string
264
- */
265
- private static formatTimeAgo(date: Date): string {
266
- const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
267
-
268
- if (seconds < 60) return `${seconds} seconds ago`;
269
- if (seconds < 3600) return `${Math.floor(seconds / 60)} minutes ago`;
270
- if (seconds < 86400) return `${Math.floor(seconds / 3600)} hours ago`;
271
- return `${Math.floor(seconds / 86400)} days ago`;
272
- }
273
-
274
- /**
275
- * Format compact status (for inline display)
276
- */
277
- static formatCompact(report: StatusReport): string {
278
- const totalEnabled = Object.values(report.tools).reduce((sum, g) => sum + g.enabled, 0);
279
- const totalAvailable = Object.values(report.tools).reduce((sum, g) => sum + g.available, 0);
280
- const symbol = report.connection.status === "connected" ? "✓" : "✗";
281
-
282
- return `MemoryRelay: ${symbol} ${report.connection.status}, ${totalAvailable}/${totalEnabled} tools working`;
283
- }
284
- }