jasper-recall 0.5.4 → 0.5.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/cli/jasper-recall.js +33 -10
- package/extensions/jasper-recall/index.ts +53 -22
- package/openclaw.plugin.json +50 -0
- package/package.json +1 -1
package/cli/jasper-recall.js
CHANGED
|
@@ -61,19 +61,33 @@ function setupOpenClawIntegration() {
|
|
|
61
61
|
return false;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
// Install
|
|
65
|
-
const
|
|
64
|
+
// Install plugin files to ~/.openclaw/extensions/jasper-recall/
|
|
65
|
+
const OPENCLAW_EXTENSIONS = path.join(openclawDir, 'extensions', 'jasper-recall');
|
|
66
|
+
const pluginSrcDir = path.join(EXTENSIONS_DIR, 'jasper-recall');
|
|
67
|
+
|
|
68
|
+
fs.mkdirSync(OPENCLAW_EXTENSIONS, { recursive: true });
|
|
69
|
+
|
|
70
|
+
const pluginFiles = ['index.ts', 'openclaw.plugin.json', 'package.json', 'SKILL.md'];
|
|
71
|
+
for (const file of pluginFiles) {
|
|
72
|
+
const src = path.join(pluginSrcDir, file);
|
|
73
|
+
const dest = path.join(OPENCLAW_EXTENSIONS, file);
|
|
74
|
+
if (fs.existsSync(src)) {
|
|
75
|
+
fs.copyFileSync(src, dest);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
console.log(` ✓ Installed plugin files: ${OPENCLAW_EXTENSIONS}`);
|
|
79
|
+
|
|
80
|
+
// Install SKILL.md to skills directory (for agent discovery)
|
|
81
|
+
const skillSrc = path.join(pluginSrcDir, 'SKILL.md');
|
|
66
82
|
const skillDest = path.join(OPENCLAW_SKILLS, 'jasper-recall', 'SKILL.md');
|
|
67
83
|
|
|
68
84
|
if (fs.existsSync(skillSrc)) {
|
|
69
85
|
fs.mkdirSync(path.dirname(skillDest), { recursive: true });
|
|
70
86
|
fs.copyFileSync(skillSrc, skillDest);
|
|
71
87
|
console.log(` ✓ Installed SKILL.md: ${skillDest}`);
|
|
72
|
-
} else {
|
|
73
|
-
console.log(' ⚠ SKILL.md not found in package (try reinstalling)');
|
|
74
88
|
}
|
|
75
89
|
|
|
76
|
-
// Update openclaw.json with plugin config
|
|
90
|
+
// Update openclaw.json with plugin config AND path
|
|
77
91
|
if (fs.existsSync(OPENCLAW_CONFIG)) {
|
|
78
92
|
try {
|
|
79
93
|
const configRaw = fs.readFileSync(OPENCLAW_CONFIG, 'utf8');
|
|
@@ -82,6 +96,14 @@ function setupOpenClawIntegration() {
|
|
|
82
96
|
// Initialize plugins structure if needed
|
|
83
97
|
if (!config.plugins) config.plugins = {};
|
|
84
98
|
if (!config.plugins.entries) config.plugins.entries = {};
|
|
99
|
+
if (!config.plugins.load) config.plugins.load = {};
|
|
100
|
+
if (!config.plugins.load.paths) config.plugins.load.paths = [];
|
|
101
|
+
|
|
102
|
+
// Add plugin path if not already present
|
|
103
|
+
if (!config.plugins.load.paths.includes(OPENCLAW_EXTENSIONS)) {
|
|
104
|
+
config.plugins.load.paths.push(OPENCLAW_EXTENSIONS);
|
|
105
|
+
console.log(` ✓ Added plugin path to plugins.load.paths`);
|
|
106
|
+
}
|
|
85
107
|
|
|
86
108
|
// Check if already configured
|
|
87
109
|
if (config.plugins.entries['jasper-recall']) {
|
|
@@ -96,12 +118,13 @@ function setupOpenClawIntegration() {
|
|
|
96
118
|
defaultLimit: 5
|
|
97
119
|
}
|
|
98
120
|
};
|
|
99
|
-
|
|
100
|
-
// Write back with nice formatting
|
|
101
|
-
fs.writeFileSync(OPENCLAW_CONFIG, JSON.stringify(config, null, 2) + '\n');
|
|
102
|
-
console.log(' ✓ Added jasper-recall plugin to openclaw.json');
|
|
103
|
-
console.log(' → Restart OpenClaw gateway to activate: openclaw gateway restart');
|
|
121
|
+
console.log(' ✓ Added jasper-recall plugin config');
|
|
104
122
|
}
|
|
123
|
+
|
|
124
|
+
// Write back with nice formatting
|
|
125
|
+
fs.writeFileSync(OPENCLAW_CONFIG, JSON.stringify(config, null, 2) + '\n');
|
|
126
|
+
console.log(' → Restart OpenClaw gateway to activate: openclaw gateway restart');
|
|
127
|
+
|
|
105
128
|
} catch (e) {
|
|
106
129
|
console.log(` ⚠ Could not update openclaw.json: ${e.message}`);
|
|
107
130
|
console.log(' → Manually add plugin config (see docs)');
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { execSync } from 'child_process';
|
|
14
|
+
import { readFileSync, existsSync } from 'fs';
|
|
14
15
|
import * as path from 'path';
|
|
15
16
|
import * as os from 'os';
|
|
16
17
|
|
|
@@ -131,18 +132,33 @@ export default function register(api: PluginApi) {
|
|
|
131
132
|
try {
|
|
132
133
|
let prependParts: string[] = [];
|
|
133
134
|
|
|
134
|
-
// If fresh session,
|
|
135
|
+
// If fresh session, inject identity files directly into context
|
|
135
136
|
if (isFreshSession) {
|
|
136
|
-
api.logger.info('[jasper-recall] Fresh session detected -
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
137
|
+
api.logger.info('[jasper-recall] Fresh session detected - injecting identity context');
|
|
138
|
+
|
|
139
|
+
const workspace = path.join(os.homedir(), '.openclaw', 'workspace');
|
|
140
|
+
const identityFiles = ['IDENTITY.md', 'SOUL.md', 'USER.md'];
|
|
141
|
+
const identityParts: string[] = [];
|
|
142
|
+
|
|
143
|
+
for (const file of identityFiles) {
|
|
144
|
+
const filePath = path.join(workspace, file);
|
|
145
|
+
if (existsSync(filePath)) {
|
|
146
|
+
try {
|
|
147
|
+
const content = readFileSync(filePath, 'utf8');
|
|
148
|
+
identityParts.push(`### ${file}\n${content}`);
|
|
149
|
+
} catch (err: any) {
|
|
150
|
+
api.logger.warn(`[jasper-recall] Failed to read ${file}: ${err.message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (identityParts.length > 0) {
|
|
156
|
+
prependParts.push(`<session-identity>
|
|
157
|
+
🔄 **Fresh session.** Your identity files:
|
|
158
|
+
|
|
159
|
+
${identityParts.join('\n\n---\n\n')}
|
|
160
|
+
</session-identity>`);
|
|
161
|
+
}
|
|
146
162
|
}
|
|
147
163
|
|
|
148
164
|
const results = runRecall(event.prompt, {
|
|
@@ -180,18 +196,33 @@ ${memoryContext}
|
|
|
180
196
|
} catch (err: any) {
|
|
181
197
|
api.logger.warn(`[jasper-recall] Auto-recall failed: ${err.message}`);
|
|
182
198
|
|
|
183
|
-
// Still inject identity
|
|
199
|
+
// Still inject identity context on fresh session even if recall fails
|
|
184
200
|
if (isFreshSession) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
201
|
+
const workspace = path.join(os.homedir(), '.openclaw', 'workspace');
|
|
202
|
+
const identityFiles = ['IDENTITY.md', 'SOUL.md', 'USER.md'];
|
|
203
|
+
const identityParts: string[] = [];
|
|
204
|
+
|
|
205
|
+
for (const file of identityFiles) {
|
|
206
|
+
const filePath = path.join(workspace, file);
|
|
207
|
+
if (existsSync(filePath)) {
|
|
208
|
+
try {
|
|
209
|
+
const content = readFileSync(filePath, 'utf8');
|
|
210
|
+
identityParts.push(`### ${file}\n${content}`);
|
|
211
|
+
} catch {
|
|
212
|
+
// Skip unreadable files
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (identityParts.length > 0) {
|
|
218
|
+
return {
|
|
219
|
+
prependContext: `<session-identity>
|
|
220
|
+
🔄 **Fresh session.** Your identity files:
|
|
221
|
+
|
|
222
|
+
${identityParts.join('\n\n---\n\n')}
|
|
223
|
+
</session-identity>`,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
195
226
|
}
|
|
196
227
|
}
|
|
197
228
|
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "jasper-recall",
|
|
3
|
+
"name": "Jasper Recall - Local RAG Memory",
|
|
4
|
+
"version": "0.2.0",
|
|
5
|
+
"description": "Semantic search over indexed memory using ChromaDB with auto-recall",
|
|
6
|
+
"homepage": "https://github.com/E-x-O-Entertainment-Studios-Inc/jasper-recall",
|
|
7
|
+
"configSchema": {
|
|
8
|
+
"type": "object",
|
|
9
|
+
"additionalProperties": false,
|
|
10
|
+
"properties": {
|
|
11
|
+
"enabled": {
|
|
12
|
+
"type": "boolean",
|
|
13
|
+
"default": true
|
|
14
|
+
},
|
|
15
|
+
"autoRecall": {
|
|
16
|
+
"type": "boolean",
|
|
17
|
+
"default": false,
|
|
18
|
+
"description": "Automatically inject relevant memories before agent processing"
|
|
19
|
+
},
|
|
20
|
+
"defaultLimit": {
|
|
21
|
+
"type": "number",
|
|
22
|
+
"default": 5,
|
|
23
|
+
"description": "Default number of results to return"
|
|
24
|
+
},
|
|
25
|
+
"minScore": {
|
|
26
|
+
"type": "number",
|
|
27
|
+
"default": 0.3,
|
|
28
|
+
"description": "Minimum similarity score for auto-recall (0-1)"
|
|
29
|
+
},
|
|
30
|
+
"publicOnly": {
|
|
31
|
+
"type": "boolean",
|
|
32
|
+
"default": false,
|
|
33
|
+
"description": "Only search public memory (for sandboxed agents)"
|
|
34
|
+
},
|
|
35
|
+
"logLevel": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"enum": ["debug", "info", "warn", "error"],
|
|
38
|
+
"default": "info"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"uiHints": {
|
|
43
|
+
"enabled": { "label": "Enable Jasper Recall" },
|
|
44
|
+
"autoRecall": { "label": "Auto-Recall", "help": "Inject relevant memories into context before processing" },
|
|
45
|
+
"defaultLimit": { "label": "Default Result Limit" },
|
|
46
|
+
"minScore": { "label": "Minimum Score", "help": "Threshold for auto-recall relevance (0.3 = 30%)" },
|
|
47
|
+
"publicOnly": { "label": "Public Memory Only" },
|
|
48
|
+
"logLevel": { "label": "Log Level" }
|
|
49
|
+
}
|
|
50
|
+
}
|