@vectorize-io/hindsight-openclaw 0.5.1 → 0.6.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 +147 -18
- package/dist/backfill-lib.d.ts +63 -0
- package/dist/backfill-lib.js +201 -0
- package/dist/backfill.d.ts +22 -0
- package/dist/backfill.js +473 -0
- package/dist/index.d.ts +49 -2
- package/dist/index.js +612 -344
- package/dist/retain-queue.d.ts +54 -0
- package/dist/retain-queue.js +105 -0
- package/dist/session-patterns.d.ts +10 -0
- package/dist/session-patterns.js +21 -0
- package/dist/setup-lib.d.ts +80 -0
- package/dist/setup-lib.js +134 -0
- package/dist/setup.d.ts +34 -0
- package/dist/setup.js +425 -0
- package/dist/types.d.ts +40 -40
- package/openclaw.plugin.json +110 -10
- package/package.json +13 -5
- package/dist/client.d.ts +0 -34
- package/dist/client.js +0 -215
- package/dist/embed-manager.d.ts +0 -27
- package/dist/embed-manager.js +0 -210
package/dist/embed-manager.js
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'child_process';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { homedir } from 'os';
|
|
4
|
-
export class HindsightEmbedManager {
|
|
5
|
-
process = null;
|
|
6
|
-
port;
|
|
7
|
-
baseUrl;
|
|
8
|
-
embedDir;
|
|
9
|
-
llmProvider;
|
|
10
|
-
llmApiKey;
|
|
11
|
-
llmModel;
|
|
12
|
-
llmBaseUrl;
|
|
13
|
-
daemonIdleTimeout;
|
|
14
|
-
embedVersion;
|
|
15
|
-
embedPackagePath;
|
|
16
|
-
constructor(port, llmProvider, llmApiKey, llmModel, llmBaseUrl, daemonIdleTimeout = 0, // Default: never timeout
|
|
17
|
-
embedVersion = 'latest', // Default: latest
|
|
18
|
-
embedPackagePath // Local path to hindsight package
|
|
19
|
-
) {
|
|
20
|
-
// Use the configured port (default: 9077 from config)
|
|
21
|
-
this.port = port;
|
|
22
|
-
this.baseUrl = `http://127.0.0.1:${port}`;
|
|
23
|
-
this.embedDir = join(homedir(), '.openclaw', 'hindsight-embed');
|
|
24
|
-
this.llmProvider = llmProvider;
|
|
25
|
-
this.llmApiKey = llmApiKey;
|
|
26
|
-
this.llmModel = llmModel;
|
|
27
|
-
this.llmBaseUrl = llmBaseUrl;
|
|
28
|
-
this.daemonIdleTimeout = daemonIdleTimeout;
|
|
29
|
-
this.embedVersion = embedVersion || 'latest';
|
|
30
|
-
this.embedPackagePath = embedPackagePath;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Get the command to run hindsight-embed (either local or from PyPI)
|
|
34
|
-
*/
|
|
35
|
-
getEmbedCommand() {
|
|
36
|
-
if (this.embedPackagePath) {
|
|
37
|
-
// Local package: uv run --directory <path> hindsight-embed
|
|
38
|
-
return ['uv', 'run', '--directory', this.embedPackagePath, 'hindsight-embed'];
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
// PyPI package: uvx hindsight-embed@version
|
|
42
|
-
const embedPackage = this.embedVersion ? `hindsight-embed@${this.embedVersion}` : 'hindsight-embed@latest';
|
|
43
|
-
return ['uvx', embedPackage];
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
async start() {
|
|
47
|
-
console.log(`[Hindsight] Starting hindsight-embed daemon...`);
|
|
48
|
-
// Build environment variables using standard HINDSIGHT_API_LLM_* variables
|
|
49
|
-
const env = {
|
|
50
|
-
...process.env,
|
|
51
|
-
HINDSIGHT_API_LLM_PROVIDER: this.llmProvider,
|
|
52
|
-
HINDSIGHT_API_LLM_API_KEY: this.llmApiKey,
|
|
53
|
-
HINDSIGHT_EMBED_DAEMON_IDLE_TIMEOUT: this.daemonIdleTimeout.toString(),
|
|
54
|
-
};
|
|
55
|
-
if (this.llmModel) {
|
|
56
|
-
env['HINDSIGHT_API_LLM_MODEL'] = this.llmModel;
|
|
57
|
-
}
|
|
58
|
-
// Pass through base URL for OpenAI-compatible providers (OpenRouter, etc.)
|
|
59
|
-
if (this.llmBaseUrl) {
|
|
60
|
-
env['HINDSIGHT_API_LLM_BASE_URL'] = this.llmBaseUrl;
|
|
61
|
-
}
|
|
62
|
-
// On macOS, force CPU for embeddings/reranker to avoid MPS/Metal issues in daemon mode
|
|
63
|
-
if (process.platform === 'darwin') {
|
|
64
|
-
env['HINDSIGHT_API_EMBEDDINGS_LOCAL_FORCE_CPU'] = '1';
|
|
65
|
-
env['HINDSIGHT_API_RERANKER_LOCAL_FORCE_CPU'] = '1';
|
|
66
|
-
}
|
|
67
|
-
// Configure "openclaw" profile using hindsight-embed configure (non-interactive)
|
|
68
|
-
console.log('[Hindsight] Configuring "openclaw" profile...');
|
|
69
|
-
await this.configureProfile(env);
|
|
70
|
-
// Start hindsight-embed daemon with openclaw profile
|
|
71
|
-
const embedCmd = this.getEmbedCommand();
|
|
72
|
-
const startDaemon = spawn(embedCmd[0], [...embedCmd.slice(1), 'daemon', '--profile', 'openclaw', 'start'], {
|
|
73
|
-
stdio: 'pipe',
|
|
74
|
-
});
|
|
75
|
-
// Collect output
|
|
76
|
-
let output = '';
|
|
77
|
-
startDaemon.stdout?.on('data', (data) => {
|
|
78
|
-
const text = data.toString();
|
|
79
|
-
output += text;
|
|
80
|
-
console.log(`[Hindsight] ${text.trim()}`);
|
|
81
|
-
});
|
|
82
|
-
startDaemon.stderr?.on('data', (data) => {
|
|
83
|
-
const text = data.toString();
|
|
84
|
-
output += text;
|
|
85
|
-
console.error(`[Hindsight] ${text.trim()}`);
|
|
86
|
-
});
|
|
87
|
-
// Wait for daemon start command to complete
|
|
88
|
-
await new Promise((resolve, reject) => {
|
|
89
|
-
startDaemon.on('exit', (code) => {
|
|
90
|
-
if (code === 0) {
|
|
91
|
-
console.log('[Hindsight] Daemon start command completed');
|
|
92
|
-
resolve();
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
reject(new Error(`Daemon start failed with code ${code}: ${output}`));
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
startDaemon.on('error', (error) => {
|
|
99
|
-
reject(error);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
// Wait for server to be ready
|
|
103
|
-
await this.waitForReady();
|
|
104
|
-
console.log('[Hindsight] Daemon is ready');
|
|
105
|
-
}
|
|
106
|
-
async stop() {
|
|
107
|
-
console.log('[Hindsight] Stopping hindsight-embed daemon...');
|
|
108
|
-
const embedCmd = this.getEmbedCommand();
|
|
109
|
-
const stopDaemon = spawn(embedCmd[0], [...embedCmd.slice(1), 'daemon', '--profile', 'openclaw', 'stop'], {
|
|
110
|
-
stdio: 'pipe',
|
|
111
|
-
});
|
|
112
|
-
await new Promise((resolve) => {
|
|
113
|
-
stopDaemon.on('exit', () => {
|
|
114
|
-
console.log('[Hindsight] Daemon stopped');
|
|
115
|
-
resolve();
|
|
116
|
-
});
|
|
117
|
-
stopDaemon.on('error', (error) => {
|
|
118
|
-
console.error('[Hindsight] Error stopping daemon:', error);
|
|
119
|
-
resolve(); // Resolve anyway
|
|
120
|
-
});
|
|
121
|
-
// Timeout after 5 seconds
|
|
122
|
-
setTimeout(() => {
|
|
123
|
-
console.log('[Hindsight] Daemon stop timeout');
|
|
124
|
-
resolve();
|
|
125
|
-
}, 5000);
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
async waitForReady(maxAttempts = 30) {
|
|
129
|
-
console.log('[Hindsight] Waiting for daemon to be ready...');
|
|
130
|
-
for (let i = 0; i < maxAttempts; i++) {
|
|
131
|
-
try {
|
|
132
|
-
const response = await fetch(`${this.baseUrl}/health`);
|
|
133
|
-
if (response.ok) {
|
|
134
|
-
console.log('[Hindsight] Daemon health check passed');
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
catch {
|
|
139
|
-
// Not ready yet
|
|
140
|
-
}
|
|
141
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
142
|
-
}
|
|
143
|
-
throw new Error('Hindsight daemon failed to become ready within 30 seconds');
|
|
144
|
-
}
|
|
145
|
-
getBaseUrl() {
|
|
146
|
-
return this.baseUrl;
|
|
147
|
-
}
|
|
148
|
-
isRunning() {
|
|
149
|
-
return this.process !== null;
|
|
150
|
-
}
|
|
151
|
-
async checkHealth() {
|
|
152
|
-
try {
|
|
153
|
-
const response = await fetch(`${this.baseUrl}/health`, { signal: AbortSignal.timeout(2000) });
|
|
154
|
-
return response.ok;
|
|
155
|
-
}
|
|
156
|
-
catch {
|
|
157
|
-
return false;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
async configureProfile(env) {
|
|
161
|
-
// Build profile create command args with --merge, --port and --env flags
|
|
162
|
-
// Use --merge to allow updating existing profile
|
|
163
|
-
const createArgs = ['profile', 'create', 'openclaw', '--merge', '--port', this.port.toString()];
|
|
164
|
-
// Add all environment variables as --env flags
|
|
165
|
-
const envVars = [
|
|
166
|
-
'HINDSIGHT_API_LLM_PROVIDER',
|
|
167
|
-
'HINDSIGHT_API_LLM_MODEL',
|
|
168
|
-
'HINDSIGHT_API_LLM_API_KEY',
|
|
169
|
-
'HINDSIGHT_API_LLM_BASE_URL',
|
|
170
|
-
'HINDSIGHT_EMBED_DAEMON_IDLE_TIMEOUT',
|
|
171
|
-
'HINDSIGHT_API_EMBEDDINGS_LOCAL_FORCE_CPU',
|
|
172
|
-
'HINDSIGHT_API_RERANKER_LOCAL_FORCE_CPU',
|
|
173
|
-
];
|
|
174
|
-
for (const envVar of envVars) {
|
|
175
|
-
if (env[envVar]) {
|
|
176
|
-
createArgs.push('--env', `${envVar}=${env[envVar]}`);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
// Run profile create command (non-interactive, overwrites if exists)
|
|
180
|
-
const embedCmd = this.getEmbedCommand();
|
|
181
|
-
const create = spawn(embedCmd[0], [...embedCmd.slice(1), ...createArgs], {
|
|
182
|
-
stdio: 'pipe',
|
|
183
|
-
});
|
|
184
|
-
let output = '';
|
|
185
|
-
create.stdout?.on('data', (data) => {
|
|
186
|
-
const text = data.toString();
|
|
187
|
-
output += text;
|
|
188
|
-
console.log(`[Hindsight] ${text.trim()}`);
|
|
189
|
-
});
|
|
190
|
-
create.stderr?.on('data', (data) => {
|
|
191
|
-
const text = data.toString();
|
|
192
|
-
output += text;
|
|
193
|
-
console.error(`[Hindsight] ${text.trim()}`);
|
|
194
|
-
});
|
|
195
|
-
await new Promise((resolve, reject) => {
|
|
196
|
-
create.on('exit', (code) => {
|
|
197
|
-
if (code === 0) {
|
|
198
|
-
console.log('[Hindsight] Profile "openclaw" configured successfully');
|
|
199
|
-
resolve();
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
reject(new Error(`Profile create failed with code ${code}: ${output}`));
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
create.on('error', (error) => {
|
|
206
|
-
reject(error);
|
|
207
|
-
});
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
}
|