@vectorize-io/hindsight-openclaw 0.4.5 → 0.4.7
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 +3 -3
- package/dist/embed-manager.d.ts +4 -1
- package/dist/embed-manager.js +92 -4
- package/dist/index.js +105 -68
- package/package.json +3 -3
- /package/{clawdbot.plugin.json → openclaw.plugin.json} +0 -0
package/README.md
CHANGED
|
@@ -7,13 +7,13 @@ Biomimetic long-term memory for [OpenClaw](https://openclaw.ai) using [Hindsight
|
|
|
7
7
|
```bash
|
|
8
8
|
# 1. Configure your LLM provider
|
|
9
9
|
export OPENAI_API_KEY="sk-your-key"
|
|
10
|
-
|
|
10
|
+
openclaw config set 'agents.defaults.models."openai/gpt-4o-mini"' '{}'
|
|
11
11
|
|
|
12
12
|
# 2. Install and enable the plugin
|
|
13
|
-
|
|
13
|
+
openclaw plugins install @vectorize-io/hindsight-openclaw
|
|
14
14
|
|
|
15
15
|
# 3. Start OpenClaw
|
|
16
|
-
|
|
16
|
+
openclaw gateway
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
That's it! The plugin will automatically start capturing and recalling memories.
|
package/dist/embed-manager.d.ts
CHANGED
|
@@ -6,13 +6,16 @@ export declare class HindsightEmbedManager {
|
|
|
6
6
|
private llmProvider;
|
|
7
7
|
private llmApiKey;
|
|
8
8
|
private llmModel?;
|
|
9
|
+
private llmBaseUrl?;
|
|
9
10
|
private daemonIdleTimeout;
|
|
10
11
|
private embedVersion;
|
|
11
|
-
constructor(port: number, llmProvider: string, llmApiKey: string, llmModel?: string, daemonIdleTimeout?: number, // Default: never timeout
|
|
12
|
+
constructor(port: number, llmProvider: string, llmApiKey: string, llmModel?: string, llmBaseUrl?: string, daemonIdleTimeout?: number, // Default: never timeout
|
|
12
13
|
embedVersion?: string);
|
|
13
14
|
start(): Promise<void>;
|
|
14
15
|
stop(): Promise<void>;
|
|
15
16
|
private waitForReady;
|
|
16
17
|
getBaseUrl(): string;
|
|
17
18
|
isRunning(): boolean;
|
|
19
|
+
checkHealth(): Promise<boolean>;
|
|
20
|
+
private writeConfigEnv;
|
|
18
21
|
}
|
package/dist/embed-manager.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
2
3
|
import { join } from 'path';
|
|
3
4
|
import { homedir } from 'os';
|
|
4
5
|
export class HindsightEmbedManager {
|
|
@@ -9,17 +10,19 @@ export class HindsightEmbedManager {
|
|
|
9
10
|
llmProvider;
|
|
10
11
|
llmApiKey;
|
|
11
12
|
llmModel;
|
|
13
|
+
llmBaseUrl;
|
|
12
14
|
daemonIdleTimeout;
|
|
13
15
|
embedVersion;
|
|
14
|
-
constructor(port, llmProvider, llmApiKey, llmModel, daemonIdleTimeout = 0, // Default: never timeout
|
|
16
|
+
constructor(port, llmProvider, llmApiKey, llmModel, llmBaseUrl, daemonIdleTimeout = 0, // Default: never timeout
|
|
15
17
|
embedVersion = 'latest' // Default: latest
|
|
16
18
|
) {
|
|
17
|
-
this.port =
|
|
18
|
-
this.baseUrl = `http://127.0.0.1:
|
|
19
|
-
this.embedDir = join(homedir(), '.
|
|
19
|
+
this.port = 8888; // hindsight-embed daemon uses same port as API
|
|
20
|
+
this.baseUrl = `http://127.0.0.1:8888`;
|
|
21
|
+
this.embedDir = join(homedir(), '.openclaw', 'hindsight-embed');
|
|
20
22
|
this.llmProvider = llmProvider;
|
|
21
23
|
this.llmApiKey = llmApiKey;
|
|
22
24
|
this.llmModel = llmModel;
|
|
25
|
+
this.llmBaseUrl = llmBaseUrl;
|
|
23
26
|
this.daemonIdleTimeout = daemonIdleTimeout;
|
|
24
27
|
this.embedVersion = embedVersion || 'latest';
|
|
25
28
|
}
|
|
@@ -35,6 +38,17 @@ export class HindsightEmbedManager {
|
|
|
35
38
|
if (this.llmModel) {
|
|
36
39
|
env['HINDSIGHT_EMBED_LLM_MODEL'] = this.llmModel;
|
|
37
40
|
}
|
|
41
|
+
// Pass through base URL for OpenAI-compatible providers (OpenRouter, etc.)
|
|
42
|
+
if (this.llmBaseUrl) {
|
|
43
|
+
env['HINDSIGHT_API_LLM_BASE_URL'] = this.llmBaseUrl;
|
|
44
|
+
}
|
|
45
|
+
// On macOS, force CPU for embeddings/reranker to avoid MPS/Metal issues in daemon mode
|
|
46
|
+
if (process.platform === 'darwin') {
|
|
47
|
+
env['HINDSIGHT_API_EMBEDDINGS_LOCAL_FORCE_CPU'] = '1';
|
|
48
|
+
env['HINDSIGHT_API_RERANKER_LOCAL_FORCE_CPU'] = '1';
|
|
49
|
+
}
|
|
50
|
+
// Write env vars to ~/.hindsight/config.env for daemon persistence
|
|
51
|
+
await this.writeConfigEnv(env);
|
|
38
52
|
// Start hindsight-embed daemon (it manages itself)
|
|
39
53
|
const embedPackage = this.embedVersion ? `hindsight-embed@${this.embedVersion}` : 'hindsight-embed@latest';
|
|
40
54
|
const startDaemon = spawn('uvx', [embedPackage, 'daemon', 'start'], {
|
|
@@ -117,4 +131,78 @@ export class HindsightEmbedManager {
|
|
|
117
131
|
isRunning() {
|
|
118
132
|
return this.process !== null;
|
|
119
133
|
}
|
|
134
|
+
async checkHealth() {
|
|
135
|
+
try {
|
|
136
|
+
const response = await fetch(`${this.baseUrl}/health`, { signal: AbortSignal.timeout(2000) });
|
|
137
|
+
return response.ok;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async writeConfigEnv(env) {
|
|
144
|
+
const hindsightDir = join(homedir(), '.hindsight');
|
|
145
|
+
const embedConfigPath = join(hindsightDir, 'embed');
|
|
146
|
+
// Ensure directory exists
|
|
147
|
+
await fs.mkdir(hindsightDir, { recursive: true });
|
|
148
|
+
// Read existing config to preserve extra settings
|
|
149
|
+
let existingContent = '';
|
|
150
|
+
let extraSettings = [];
|
|
151
|
+
try {
|
|
152
|
+
existingContent = await fs.readFile(embedConfigPath, 'utf-8');
|
|
153
|
+
// Extract non-LLM settings (like FORCE_CPU flags)
|
|
154
|
+
const lines = existingContent.split('\n');
|
|
155
|
+
for (const line of lines) {
|
|
156
|
+
const trimmed = line.trim();
|
|
157
|
+
if (trimmed && !trimmed.startsWith('#') &&
|
|
158
|
+
!trimmed.startsWith('HINDSIGHT_EMBED_LLM_') &&
|
|
159
|
+
!trimmed.startsWith('HINDSIGHT_API_LLM_') &&
|
|
160
|
+
!trimmed.startsWith('HINDSIGHT_EMBED_BANK_ID') &&
|
|
161
|
+
!trimmed.startsWith('HINDSIGHT_EMBED_DAEMON_IDLE_TIMEOUT')) {
|
|
162
|
+
extraSettings.push(line);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// File doesn't exist yet, that's fine
|
|
168
|
+
}
|
|
169
|
+
// Build config file with header
|
|
170
|
+
const configLines = [
|
|
171
|
+
'# Hindsight Embed Configuration',
|
|
172
|
+
'# Generated by OpenClaw Hindsight plugin',
|
|
173
|
+
'',
|
|
174
|
+
];
|
|
175
|
+
// Add LLM config
|
|
176
|
+
if (env.HINDSIGHT_EMBED_LLM_PROVIDER) {
|
|
177
|
+
configLines.push(`HINDSIGHT_EMBED_LLM_PROVIDER=${env.HINDSIGHT_EMBED_LLM_PROVIDER}`);
|
|
178
|
+
}
|
|
179
|
+
if (env.HINDSIGHT_EMBED_LLM_MODEL) {
|
|
180
|
+
configLines.push(`HINDSIGHT_EMBED_LLM_MODEL=${env.HINDSIGHT_EMBED_LLM_MODEL}`);
|
|
181
|
+
}
|
|
182
|
+
if (env.HINDSIGHT_EMBED_LLM_API_KEY) {
|
|
183
|
+
configLines.push(`HINDSIGHT_EMBED_LLM_API_KEY=${env.HINDSIGHT_EMBED_LLM_API_KEY}`);
|
|
184
|
+
}
|
|
185
|
+
if (env.HINDSIGHT_API_LLM_BASE_URL) {
|
|
186
|
+
configLines.push(`HINDSIGHT_API_LLM_BASE_URL=${env.HINDSIGHT_API_LLM_BASE_URL}`);
|
|
187
|
+
}
|
|
188
|
+
if (env.HINDSIGHT_EMBED_DAEMON_IDLE_TIMEOUT) {
|
|
189
|
+
configLines.push(`HINDSIGHT_EMBED_DAEMON_IDLE_TIMEOUT=${env.HINDSIGHT_EMBED_DAEMON_IDLE_TIMEOUT}`);
|
|
190
|
+
}
|
|
191
|
+
// Add platform-specific config (macOS FORCE_CPU flags)
|
|
192
|
+
if (env.HINDSIGHT_API_EMBEDDINGS_LOCAL_FORCE_CPU) {
|
|
193
|
+
configLines.push(`HINDSIGHT_API_EMBEDDINGS_LOCAL_FORCE_CPU=${env.HINDSIGHT_API_EMBEDDINGS_LOCAL_FORCE_CPU}`);
|
|
194
|
+
}
|
|
195
|
+
if (env.HINDSIGHT_API_RERANKER_LOCAL_FORCE_CPU) {
|
|
196
|
+
configLines.push(`HINDSIGHT_API_RERANKER_LOCAL_FORCE_CPU=${env.HINDSIGHT_API_RERANKER_LOCAL_FORCE_CPU}`);
|
|
197
|
+
}
|
|
198
|
+
// Add extra settings if they exist
|
|
199
|
+
if (extraSettings.length > 0) {
|
|
200
|
+
configLines.push('');
|
|
201
|
+
configLines.push('# Additional settings');
|
|
202
|
+
configLines.push(...extraSettings);
|
|
203
|
+
}
|
|
204
|
+
// Write to file
|
|
205
|
+
await fs.writeFile(embedConfigPath, configLines.join('\n') + '\n', 'utf-8');
|
|
206
|
+
console.log(`[Hindsight] Wrote config to ${embedConfigPath}`);
|
|
207
|
+
}
|
|
120
208
|
}
|
package/dist/index.js
CHANGED
|
@@ -24,69 +24,65 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
24
24
|
const __dirname = dirname(__filename);
|
|
25
25
|
// Default bank name
|
|
26
26
|
const BANK_NAME = 'openclaw';
|
|
27
|
-
// Provider
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
'
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
//
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// Get models from config (agents.defaults.models is a dictionary of models)
|
|
47
|
-
const models = api.config.agents?.defaults?.models;
|
|
48
|
-
if (!models || Object.keys(models).length === 0) {
|
|
49
|
-
throw new Error('No models configured in Moltbot. Please configure at least one model in agents.defaults.models');
|
|
50
|
-
}
|
|
51
|
-
// Try all configured models to find one with an available API key
|
|
52
|
-
const configuredModels = Object.keys(models);
|
|
53
|
-
for (const modelKey of configuredModels) {
|
|
54
|
-
const [moltbotProvider, ...modelParts] = modelKey.split('/');
|
|
55
|
-
const model = modelParts.join('/');
|
|
56
|
-
const hindsightProvider = PROVIDER_MAP[moltbotProvider];
|
|
57
|
-
if (!hindsightProvider) {
|
|
58
|
-
continue; // Skip unsupported providers
|
|
27
|
+
// Provider detection from standard env vars
|
|
28
|
+
const PROVIDER_DETECTION = [
|
|
29
|
+
{ name: 'openai', keyEnv: 'OPENAI_API_KEY', defaultModel: 'gpt-4o-mini' },
|
|
30
|
+
{ name: 'anthropic', keyEnv: 'ANTHROPIC_API_KEY', defaultModel: 'claude-3-5-haiku-20241022' },
|
|
31
|
+
{ name: 'gemini', keyEnv: 'GEMINI_API_KEY', defaultModel: 'gemini-2.5-flash' },
|
|
32
|
+
{ name: 'groq', keyEnv: 'GROQ_API_KEY', defaultModel: 'openai/gpt-oss-20b' },
|
|
33
|
+
{ name: 'ollama', keyEnv: '', defaultModel: 'llama3.2' },
|
|
34
|
+
];
|
|
35
|
+
function detectLLMConfig() {
|
|
36
|
+
// Override values from HINDSIGHT_API_LLM_* env vars (highest priority)
|
|
37
|
+
const overrideProvider = process.env.HINDSIGHT_API_LLM_PROVIDER;
|
|
38
|
+
const overrideModel = process.env.HINDSIGHT_API_LLM_MODEL;
|
|
39
|
+
const overrideKey = process.env.HINDSIGHT_API_LLM_API_KEY;
|
|
40
|
+
const overrideBaseUrl = process.env.HINDSIGHT_API_LLM_BASE_URL;
|
|
41
|
+
// If provider is explicitly set, use that (with overrides)
|
|
42
|
+
if (overrideProvider) {
|
|
43
|
+
if (!overrideKey && overrideProvider !== 'ollama') {
|
|
44
|
+
throw new Error(`HINDSIGHT_API_LLM_PROVIDER is set to "${overrideProvider}" but HINDSIGHT_API_LLM_API_KEY is not set.\n` +
|
|
45
|
+
`Please set: export HINDSIGHT_API_LLM_API_KEY=your-api-key`);
|
|
59
46
|
}
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
47
|
+
const providerInfo = PROVIDER_DETECTION.find(p => p.name === overrideProvider);
|
|
48
|
+
return {
|
|
49
|
+
provider: overrideProvider,
|
|
50
|
+
apiKey: overrideKey || '',
|
|
51
|
+
model: overrideModel || (providerInfo?.defaultModel),
|
|
52
|
+
baseUrl: overrideBaseUrl,
|
|
53
|
+
source: 'HINDSIGHT_API_LLM_PROVIDER override',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
// Auto-detect from standard provider env vars
|
|
57
|
+
for (const providerInfo of PROVIDER_DETECTION) {
|
|
58
|
+
const apiKey = providerInfo.keyEnv ? process.env[providerInfo.keyEnv] : '';
|
|
59
|
+
// Skip ollama in auto-detection (must be explicitly requested)
|
|
60
|
+
if (providerInfo.name === 'ollama') {
|
|
61
|
+
continue;
|
|
65
62
|
}
|
|
66
|
-
// If we found a key, use this provider
|
|
67
63
|
if (apiKey) {
|
|
68
|
-
return {
|
|
64
|
+
return {
|
|
65
|
+
provider: providerInfo.name,
|
|
66
|
+
apiKey,
|
|
67
|
+
model: overrideModel || providerInfo.defaultModel,
|
|
68
|
+
baseUrl: overrideBaseUrl, // Only use explicit HINDSIGHT_API_LLM_BASE_URL
|
|
69
|
+
source: `auto-detected from ${providerInfo.keyEnv}`,
|
|
70
|
+
};
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
|
-
// No
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
`
|
|
84
|
-
`Please set one of these environment variables:\n${keyInstructions}\n\n` +
|
|
85
|
-
`You can set them in your shell profile (~/.zshrc or ~/.bashrc):\n` +
|
|
86
|
-
` export ANTHROPIC_API_KEY="your-key-here"\n\n` +
|
|
87
|
-
`Or run Moltbot with the environment variable:\n` +
|
|
88
|
-
` ANTHROPIC_API_KEY="your-key" clawdbot start\n\n` +
|
|
89
|
-
`Alternatively, configure ollama provider which doesn't require an API key.`);
|
|
73
|
+
// No configuration found - show helpful error
|
|
74
|
+
throw new Error(`No LLM configuration found for Hindsight memory plugin.\n\n` +
|
|
75
|
+
`Option 1: Set a standard provider API key (auto-detect):\n` +
|
|
76
|
+
` export OPENAI_API_KEY=sk-your-key # Uses gpt-4o-mini\n` +
|
|
77
|
+
` export ANTHROPIC_API_KEY=your-key # Uses claude-3-5-haiku\n` +
|
|
78
|
+
` export GEMINI_API_KEY=your-key # Uses gemini-2.0-flash-exp\n` +
|
|
79
|
+
` export GROQ_API_KEY=your-key # Uses llama-3.3-70b-versatile\n\n` +
|
|
80
|
+
`Option 2: Override with Hindsight-specific config:\n` +
|
|
81
|
+
` export HINDSIGHT_API_LLM_PROVIDER=openai\n` +
|
|
82
|
+
` export HINDSIGHT_API_LLM_MODEL=gpt-4o-mini\n` +
|
|
83
|
+
` export HINDSIGHT_API_LLM_API_KEY=sk-your-key\n` +
|
|
84
|
+
` export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1 # Optional\n\n` +
|
|
85
|
+
`Tip: Use a cheap/fast model for memory extraction (e.g., gpt-4o-mini, claude-3-5-haiku, or free models on OpenRouter)`);
|
|
90
86
|
}
|
|
91
87
|
function getPluginConfig(api) {
|
|
92
88
|
const config = api.config.plugins?.entries?.['hindsight-openclaw']?.config || {};
|
|
@@ -101,14 +97,16 @@ function getPluginConfig(api) {
|
|
|
101
97
|
export default function (api) {
|
|
102
98
|
try {
|
|
103
99
|
console.log('[Hindsight] Plugin loading...');
|
|
104
|
-
// Detect LLM configuration from
|
|
100
|
+
// Detect LLM configuration from environment
|
|
105
101
|
console.log('[Hindsight] Detecting LLM config...');
|
|
106
|
-
const llmConfig = detectLLMConfig(
|
|
102
|
+
const llmConfig = detectLLMConfig();
|
|
103
|
+
const baseUrlInfo = llmConfig.baseUrl ? `, base URL: ${llmConfig.baseUrl}` : '';
|
|
104
|
+
const modelInfo = llmConfig.model || 'default';
|
|
107
105
|
if (llmConfig.provider === 'ollama') {
|
|
108
|
-
console.log(`[Hindsight] ✓ Using provider: ${llmConfig.provider}, model: ${llmConfig.
|
|
106
|
+
console.log(`[Hindsight] ✓ Using provider: ${llmConfig.provider}, model: ${modelInfo} (${llmConfig.source})`);
|
|
109
107
|
}
|
|
110
108
|
else {
|
|
111
|
-
console.log(`[Hindsight] ✓ Using provider: ${llmConfig.provider}, model: ${
|
|
109
|
+
console.log(`[Hindsight] ✓ Using provider: ${llmConfig.provider}, model: ${modelInfo} (${llmConfig.source}${baseUrlInfo})`);
|
|
112
110
|
}
|
|
113
111
|
console.log('[Hindsight] Getting plugin config...');
|
|
114
112
|
const pluginConfig = getPluginConfig(api);
|
|
@@ -125,7 +123,7 @@ export default function (api) {
|
|
|
125
123
|
try {
|
|
126
124
|
// Initialize embed manager
|
|
127
125
|
console.log('[Hindsight] Creating HindsightEmbedManager...');
|
|
128
|
-
embedManager = new HindsightEmbedManager(port, llmConfig.provider, llmConfig.apiKey, llmConfig.model, pluginConfig.daemonIdleTimeout, pluginConfig.embedVersion);
|
|
126
|
+
embedManager = new HindsightEmbedManager(port, llmConfig.provider, llmConfig.apiKey, llmConfig.model, llmConfig.baseUrl, pluginConfig.daemonIdleTimeout, pluginConfig.embedVersion);
|
|
129
127
|
// Start the embedded server
|
|
130
128
|
console.log('[Hindsight] Starting embedded server...');
|
|
131
129
|
await embedManager.start();
|
|
@@ -154,10 +152,46 @@ export default function (api) {
|
|
|
154
152
|
api.registerService({
|
|
155
153
|
id: 'hindsight-memory',
|
|
156
154
|
async start() {
|
|
155
|
+
console.log('[Hindsight] Service start called - checking daemon health...');
|
|
157
156
|
// Wait for background init if still pending
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
157
|
+
if (initPromise) {
|
|
158
|
+
try {
|
|
159
|
+
await initPromise;
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
console.error('[Hindsight] Initial initialization failed:', error);
|
|
163
|
+
// Continue to health check below
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Check if daemon is actually healthy (handles SIGUSR1 restart case)
|
|
167
|
+
if (embedManager && isInitialized) {
|
|
168
|
+
const healthy = await embedManager.checkHealth();
|
|
169
|
+
if (healthy) {
|
|
170
|
+
console.log('[Hindsight] Daemon is healthy');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
console.log('[Hindsight] Daemon is not responding - reinitializing...');
|
|
174
|
+
// Reset state for reinitialization
|
|
175
|
+
embedManager = null;
|
|
176
|
+
client = null;
|
|
177
|
+
isInitialized = false;
|
|
178
|
+
}
|
|
179
|
+
// Reinitialize if needed (fresh start or recovery from dead daemon)
|
|
180
|
+
if (!isInitialized) {
|
|
181
|
+
console.log('[Hindsight] Reinitializing daemon...');
|
|
182
|
+
const llmConfig = detectLLMConfig();
|
|
183
|
+
const pluginConfig = getPluginConfig(api);
|
|
184
|
+
const port = pluginConfig.embedPort || Math.floor(Math.random() * 10000) + 10000;
|
|
185
|
+
embedManager = new HindsightEmbedManager(port, llmConfig.provider, llmConfig.apiKey, llmConfig.model, llmConfig.baseUrl, pluginConfig.daemonIdleTimeout, pluginConfig.embedVersion);
|
|
186
|
+
await embedManager.start();
|
|
187
|
+
client = new HindsightClient(llmConfig.provider, llmConfig.apiKey, llmConfig.model, pluginConfig.embedVersion);
|
|
188
|
+
client.setBankId(BANK_NAME);
|
|
189
|
+
if (pluginConfig.bankMission) {
|
|
190
|
+
await client.setBankMission(pluginConfig.bankMission);
|
|
191
|
+
}
|
|
192
|
+
isInitialized = true;
|
|
193
|
+
console.log('[Hindsight] Reinitialization complete');
|
|
194
|
+
}
|
|
161
195
|
},
|
|
162
196
|
async stop() {
|
|
163
197
|
try {
|
|
@@ -215,10 +249,10 @@ export default function (api) {
|
|
|
215
249
|
return;
|
|
216
250
|
}
|
|
217
251
|
console.log('[Hindsight] Auto-recall for prompt:', prompt.substring(0, 50));
|
|
218
|
-
// Recall relevant memories (up to
|
|
252
|
+
// Recall relevant memories (up to 512 tokens)
|
|
219
253
|
const response = await client.recall({
|
|
220
254
|
query: prompt,
|
|
221
|
-
max_tokens:
|
|
255
|
+
max_tokens: 512,
|
|
222
256
|
});
|
|
223
257
|
if (!response.results || response.results.length === 0) {
|
|
224
258
|
console.log('[Hindsight] No memories found for auto-recall');
|
|
@@ -227,7 +261,10 @@ export default function (api) {
|
|
|
227
261
|
// Format memories as JSON with all fields from recall
|
|
228
262
|
const memoriesJson = JSON.stringify(response.results, null, 2);
|
|
229
263
|
const contextMessage = `<hindsight_memories>
|
|
264
|
+
Relevant memories from past conversations (score 1=highest, prioritize recent when conflicting):
|
|
230
265
|
${memoriesJson}
|
|
266
|
+
|
|
267
|
+
User message: ${prompt}
|
|
231
268
|
</hindsight_memories>`;
|
|
232
269
|
console.log(`[Hindsight] Auto-recall: Injecting ${response.results.length} memories`);
|
|
233
270
|
// Inject context before the user message
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vectorize-io/hindsight-openclaw",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "Hindsight memory plugin for OpenClaw - biomimetic long-term memory with fact extraction",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
|
-
"
|
|
8
|
+
"openclaw": {
|
|
9
9
|
"extensions": [
|
|
10
10
|
"./dist/index.js"
|
|
11
11
|
]
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"dist",
|
|
30
|
-
"
|
|
30
|
+
"openclaw.plugin.json",
|
|
31
31
|
"README.md"
|
|
32
32
|
],
|
|
33
33
|
"scripts": {
|
|
File without changes
|