@askexenow/exe-os 0.9.7 → 0.9.9
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/dist/bin/backfill-conversations.js +953 -105
- package/dist/bin/backfill-responses.js +952 -104
- package/dist/bin/backfill-vectors.js +956 -108
- package/dist/bin/cleanup-stale-review-tasks.js +802 -58
- package/dist/bin/cli.js +2292 -1070
- package/dist/bin/exe-agent-config.js +157 -101
- package/dist/bin/exe-agent.js +55 -29
- package/dist/bin/exe-assign.js +940 -92
- package/dist/bin/exe-boot.js +1424 -442
- package/dist/bin/exe-call.js +240 -141
- package/dist/bin/exe-cloud.js +198 -70
- package/dist/bin/exe-dispatch.js +951 -192
- package/dist/bin/exe-doctor.js +791 -51
- package/dist/bin/exe-export-behaviors.js +790 -42
- package/dist/bin/exe-forget.js +771 -31
- package/dist/bin/exe-gateway.js +1592 -521
- package/dist/bin/exe-heartbeat.js +850 -109
- package/dist/bin/exe-kill.js +783 -35
- package/dist/bin/exe-launch-agent.js +1030 -107
- package/dist/bin/exe-link.js +916 -110
- package/dist/bin/exe-new-employee.js +526 -217
- package/dist/bin/exe-pending-messages.js +1046 -62
- package/dist/bin/exe-pending-notifications.js +1318 -111
- package/dist/bin/exe-pending-reviews.js +1040 -72
- package/dist/bin/exe-rename.js +772 -59
- package/dist/bin/exe-review.js +772 -32
- package/dist/bin/exe-search.js +982 -128
- package/dist/bin/exe-session-cleanup.js +1180 -306
- package/dist/bin/exe-settings.js +185 -105
- package/dist/bin/exe-start-codex.js +886 -132
- package/dist/bin/exe-start-opencode.js +873 -119
- package/dist/bin/exe-status.js +803 -59
- package/dist/bin/exe-team.js +772 -32
- package/dist/bin/git-sweep.js +1046 -223
- package/dist/bin/graph-backfill.js +779 -31
- package/dist/bin/graph-export.js +785 -37
- package/dist/bin/install.js +632 -200
- package/dist/bin/scan-tasks.js +1055 -232
- package/dist/bin/setup.js +1419 -320
- package/dist/bin/shard-migrate.js +783 -35
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +782 -34
- package/dist/gateway/index.js +1444 -449
- package/dist/hooks/bug-report-worker.js +1141 -269
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +1044 -221
- package/dist/hooks/error-recall.js +989 -135
- package/dist/hooks/exe-heartbeat-hook.js +99 -75
- package/dist/hooks/ingest-worker.js +4176 -3226
- package/dist/hooks/ingest.js +920 -168
- package/dist/hooks/instructions-loaded.js +874 -70
- package/dist/hooks/notification.js +860 -56
- package/dist/hooks/post-compact.js +881 -73
- package/dist/hooks/pre-compact.js +1050 -227
- package/dist/hooks/pre-tool-use.js +1084 -159
- package/dist/hooks/prompt-ingest-worker.js +1089 -164
- package/dist/hooks/prompt-submit.js +1469 -515
- package/dist/hooks/response-ingest-worker.js +1104 -179
- package/dist/hooks/session-end.js +1085 -251
- package/dist/hooks/session-start.js +1241 -231
- package/dist/hooks/stop.js +935 -109
- package/dist/hooks/subagent-stop.js +881 -73
- package/dist/hooks/summary-worker.js +1323 -307
- package/dist/index.js +1449 -452
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +909 -115
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +42 -9
- package/dist/lib/database.js +739 -33
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +2359 -0
- package/dist/lib/device-registry.js +760 -47
- package/dist/lib/embedder.js +201 -73
- package/dist/lib/employee-templates.js +30 -4
- package/dist/lib/employees.js +290 -86
- package/dist/lib/exe-daemon-client.js +187 -83
- package/dist/lib/exe-daemon.js +1696 -616
- package/dist/lib/hybrid-search.js +982 -128
- package/dist/lib/identity.js +43 -13
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +167 -80
- package/dist/lib/reminders.js +35 -5
- package/dist/lib/schedules.js +772 -32
- package/dist/lib/skill-learning.js +54 -7
- package/dist/lib/store.js +779 -31
- package/dist/lib/task-router.js +94 -73
- package/dist/lib/tasks.js +298 -225
- package/dist/lib/tmux-routing.js +246 -172
- package/dist/lib/token-spend.js +52 -14
- package/dist/mcp/server.js +2893 -850
- package/dist/mcp/tools/complete-reminder.js +35 -5
- package/dist/mcp/tools/create-reminder.js +35 -5
- package/dist/mcp/tools/create-task.js +507 -323
- package/dist/mcp/tools/deactivate-behavior.js +40 -10
- package/dist/mcp/tools/list-reminders.js +35 -5
- package/dist/mcp/tools/list-tasks.js +277 -104
- package/dist/mcp/tools/send-message.js +129 -56
- package/dist/mcp/tools/update-task.js +1864 -188
- package/dist/runtime/index.js +1083 -259
- package/dist/tui/App.js +1501 -434
- package/package.json +3 -2
|
@@ -3,21 +3,42 @@ import net from "net";
|
|
|
3
3
|
import os2 from "os";
|
|
4
4
|
import { spawn } from "child_process";
|
|
5
5
|
import { randomUUID } from "crypto";
|
|
6
|
-
import { existsSync as
|
|
7
|
-
import
|
|
6
|
+
import { existsSync as existsSync4, unlinkSync, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
|
|
7
|
+
import path3 from "path";
|
|
8
8
|
import { fileURLToPath } from "url";
|
|
9
9
|
|
|
10
10
|
// src/lib/config.ts
|
|
11
|
-
import { readFile, writeFile
|
|
12
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
11
|
+
import { readFile, writeFile } from "fs/promises";
|
|
12
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
13
13
|
import path from "path";
|
|
14
14
|
import os from "os";
|
|
15
|
+
|
|
16
|
+
// src/lib/secure-files.ts
|
|
17
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
18
|
+
import { chmod, mkdir } from "fs/promises";
|
|
19
|
+
var PRIVATE_DIR_MODE = 448;
|
|
20
|
+
var PRIVATE_FILE_MODE = 384;
|
|
21
|
+
function ensurePrivateDirSync(dirPath) {
|
|
22
|
+
mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
23
|
+
try {
|
|
24
|
+
chmodSync(dirPath, PRIVATE_DIR_MODE);
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function enforcePrivateFileSync(filePath) {
|
|
29
|
+
try {
|
|
30
|
+
if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
31
|
+
} catch {
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/lib/config.ts
|
|
15
36
|
function resolveDataDir() {
|
|
16
37
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
17
38
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
18
39
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
19
40
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
20
|
-
if (!
|
|
41
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
21
42
|
try {
|
|
22
43
|
renameSync(legacyDir, newDir);
|
|
23
44
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -92,18 +113,52 @@ var DEFAULT_CONFIG = {
|
|
|
92
113
|
}
|
|
93
114
|
};
|
|
94
115
|
|
|
116
|
+
// src/lib/daemon-auth.ts
|
|
117
|
+
import crypto from "crypto";
|
|
118
|
+
import path2 from "path";
|
|
119
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
120
|
+
var DAEMON_TOKEN_PATH = path2.join(EXE_AI_DIR, "exed.token");
|
|
121
|
+
function normalizeToken(token) {
|
|
122
|
+
if (!token) return null;
|
|
123
|
+
const trimmed = token.trim();
|
|
124
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
125
|
+
}
|
|
126
|
+
function readDaemonToken() {
|
|
127
|
+
try {
|
|
128
|
+
if (!existsSync3(DAEMON_TOKEN_PATH)) return null;
|
|
129
|
+
return normalizeToken(readFileSync2(DAEMON_TOKEN_PATH, "utf8"));
|
|
130
|
+
} catch {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
function ensureDaemonToken(seed) {
|
|
135
|
+
const existing = readDaemonToken();
|
|
136
|
+
if (existing) return existing;
|
|
137
|
+
const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
|
|
138
|
+
ensurePrivateDirSync(EXE_AI_DIR);
|
|
139
|
+
writeFileSync(DAEMON_TOKEN_PATH, `${token}
|
|
140
|
+
`, "utf8");
|
|
141
|
+
enforcePrivateFileSync(DAEMON_TOKEN_PATH);
|
|
142
|
+
return token;
|
|
143
|
+
}
|
|
144
|
+
|
|
95
145
|
// src/lib/exe-daemon-client.ts
|
|
96
|
-
var SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
97
|
-
var PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
98
|
-
var SPAWN_LOCK_PATH =
|
|
146
|
+
var SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path3.join(EXE_AI_DIR, "exed.sock");
|
|
147
|
+
var PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path3.join(EXE_AI_DIR, "exed.pid");
|
|
148
|
+
var SPAWN_LOCK_PATH = path3.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
99
149
|
var SPAWN_LOCK_STALE_MS = 3e4;
|
|
100
150
|
var CONNECT_TIMEOUT_MS = 15e3;
|
|
101
151
|
var REQUEST_TIMEOUT_MS = 3e4;
|
|
152
|
+
var DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
|
|
102
153
|
var _socket = null;
|
|
103
154
|
var _connected = false;
|
|
104
155
|
var _buffer = "";
|
|
105
156
|
var _requestCount = 0;
|
|
157
|
+
var _consecutiveFailures = 0;
|
|
106
158
|
var HEALTH_CHECK_INTERVAL = 100;
|
|
159
|
+
var MAX_RETRIES_BEFORE_RESTART = 3;
|
|
160
|
+
var RETRY_DELAYS_MS = [1e3, 3e3, 5e3];
|
|
161
|
+
var MIN_DAEMON_AGE_MS = 3e4;
|
|
107
162
|
var _pending = /* @__PURE__ */ new Map();
|
|
108
163
|
var MAX_BUFFER = 1e7;
|
|
109
164
|
function handleData(chunk) {
|
|
@@ -132,9 +187,9 @@ function handleData(chunk) {
|
|
|
132
187
|
}
|
|
133
188
|
}
|
|
134
189
|
function cleanupStaleFiles() {
|
|
135
|
-
if (
|
|
190
|
+
if (existsSync4(PID_PATH)) {
|
|
136
191
|
try {
|
|
137
|
-
const pid = parseInt(
|
|
192
|
+
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
138
193
|
if (pid > 0) {
|
|
139
194
|
try {
|
|
140
195
|
process.kill(pid, 0);
|
|
@@ -155,11 +210,11 @@ function cleanupStaleFiles() {
|
|
|
155
210
|
}
|
|
156
211
|
}
|
|
157
212
|
function findPackageRoot() {
|
|
158
|
-
let dir =
|
|
159
|
-
const { root } =
|
|
213
|
+
let dir = path3.dirname(fileURLToPath(import.meta.url));
|
|
214
|
+
const { root } = path3.parse(dir);
|
|
160
215
|
while (dir !== root) {
|
|
161
|
-
if (
|
|
162
|
-
dir =
|
|
216
|
+
if (existsSync4(path3.join(dir, "package.json"))) return dir;
|
|
217
|
+
dir = path3.dirname(dir);
|
|
163
218
|
}
|
|
164
219
|
return null;
|
|
165
220
|
}
|
|
@@ -185,16 +240,17 @@ function spawnDaemon() {
|
|
|
185
240
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
186
241
|
return;
|
|
187
242
|
}
|
|
188
|
-
const daemonPath =
|
|
189
|
-
if (!
|
|
243
|
+
const daemonPath = path3.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
244
|
+
if (!existsSync4(daemonPath)) {
|
|
190
245
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
191
246
|
`);
|
|
192
247
|
return;
|
|
193
248
|
}
|
|
194
249
|
const resolvedPath = daemonPath;
|
|
250
|
+
const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
|
|
195
251
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
196
252
|
`);
|
|
197
|
-
const logPath =
|
|
253
|
+
const logPath = path3.join(path3.dirname(SOCKET_PATH), "exed.log");
|
|
198
254
|
let stderrFd = "ignore";
|
|
199
255
|
try {
|
|
200
256
|
stderrFd = openSync(logPath, "a");
|
|
@@ -212,7 +268,8 @@ function spawnDaemon() {
|
|
|
212
268
|
TMUX_PANE: void 0,
|
|
213
269
|
// Prevents resolveExeSession() from scoping to one session
|
|
214
270
|
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
215
|
-
EXE_DAEMON_PID: PID_PATH
|
|
271
|
+
EXE_DAEMON_PID: PID_PATH,
|
|
272
|
+
[DAEMON_TOKEN_ENV]: daemonToken
|
|
216
273
|
}
|
|
217
274
|
});
|
|
218
275
|
child.unref();
|
|
@@ -322,13 +379,14 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
|
322
379
|
return;
|
|
323
380
|
}
|
|
324
381
|
const id = randomUUID();
|
|
382
|
+
const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
|
|
325
383
|
const timer = setTimeout(() => {
|
|
326
384
|
_pending.delete(id);
|
|
327
385
|
resolve({ error: "Request timeout" });
|
|
328
386
|
}, timeoutMs);
|
|
329
387
|
_pending.set(id, { resolve, timer });
|
|
330
388
|
try {
|
|
331
|
-
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
389
|
+
_socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
|
|
332
390
|
} catch {
|
|
333
391
|
clearTimeout(timer);
|
|
334
392
|
_pending.delete(id);
|
|
@@ -345,98 +403,132 @@ async function pingDaemon() {
|
|
|
345
403
|
return null;
|
|
346
404
|
}
|
|
347
405
|
function killAndRespawnDaemon() {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
406
|
+
if (!acquireSpawnLock()) {
|
|
407
|
+
process.stderr.write("[exed-client] Another process is already restarting daemon \u2014 skipping\n");
|
|
408
|
+
if (_socket) {
|
|
409
|
+
_socket.destroy();
|
|
410
|
+
_socket = null;
|
|
411
|
+
}
|
|
412
|
+
_connected = false;
|
|
413
|
+
_buffer = "";
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
try {
|
|
417
|
+
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
418
|
+
if (existsSync4(PID_PATH)) {
|
|
419
|
+
try {
|
|
420
|
+
const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
|
|
421
|
+
if (pid > 0) {
|
|
422
|
+
try {
|
|
423
|
+
process.kill(pid, "SIGKILL");
|
|
424
|
+
} catch {
|
|
425
|
+
}
|
|
356
426
|
}
|
|
427
|
+
} catch {
|
|
357
428
|
}
|
|
429
|
+
}
|
|
430
|
+
if (_socket) {
|
|
431
|
+
_socket.destroy();
|
|
432
|
+
_socket = null;
|
|
433
|
+
}
|
|
434
|
+
_connected = false;
|
|
435
|
+
_buffer = "";
|
|
436
|
+
try {
|
|
437
|
+
unlinkSync(PID_PATH);
|
|
358
438
|
} catch {
|
|
359
439
|
}
|
|
440
|
+
try {
|
|
441
|
+
unlinkSync(SOCKET_PATH);
|
|
442
|
+
} catch {
|
|
443
|
+
}
|
|
444
|
+
spawnDaemon();
|
|
445
|
+
} finally {
|
|
446
|
+
releaseSpawnLock();
|
|
360
447
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
_socket = null;
|
|
364
|
-
}
|
|
365
|
-
_connected = false;
|
|
366
|
-
_buffer = "";
|
|
448
|
+
}
|
|
449
|
+
function isDaemonTooYoung() {
|
|
367
450
|
try {
|
|
368
|
-
|
|
451
|
+
const stat = statSync(PID_PATH);
|
|
452
|
+
return Date.now() - stat.mtimeMs < MIN_DAEMON_AGE_MS;
|
|
369
453
|
} catch {
|
|
454
|
+
return false;
|
|
370
455
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
456
|
+
}
|
|
457
|
+
async function retryThenRestart(doRequest, label) {
|
|
458
|
+
const result = await doRequest();
|
|
459
|
+
if (!result.error) {
|
|
460
|
+
_consecutiveFailures = 0;
|
|
461
|
+
return result;
|
|
374
462
|
}
|
|
375
|
-
|
|
463
|
+
_consecutiveFailures++;
|
|
464
|
+
for (let i = 0; i < MAX_RETRIES_BEFORE_RESTART; i++) {
|
|
465
|
+
const delayMs = RETRY_DELAYS_MS[i] ?? 5e3;
|
|
466
|
+
process.stderr.write(`[exed-client] ${label} failed (${result.error}), retry ${i + 1}/${MAX_RETRIES_BEFORE_RESTART} in ${delayMs}ms
|
|
467
|
+
`);
|
|
468
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
469
|
+
if (!_connected) {
|
|
470
|
+
if (!await connectToSocket()) continue;
|
|
471
|
+
}
|
|
472
|
+
const retry = await doRequest();
|
|
473
|
+
if (!retry.error) {
|
|
474
|
+
_consecutiveFailures = 0;
|
|
475
|
+
return retry;
|
|
476
|
+
}
|
|
477
|
+
_consecutiveFailures++;
|
|
478
|
+
}
|
|
479
|
+
if (isDaemonTooYoung()) {
|
|
480
|
+
process.stderr.write(`[exed-client] ${label}: daemon too young (< ${MIN_DAEMON_AGE_MS / 1e3}s) \u2014 skipping restart
|
|
481
|
+
`);
|
|
482
|
+
return { error: result.error };
|
|
483
|
+
}
|
|
484
|
+
process.stderr.write(`[exed-client] ${label}: ${_consecutiveFailures} consecutive failures \u2014 restarting daemon
|
|
485
|
+
`);
|
|
486
|
+
killAndRespawnDaemon();
|
|
487
|
+
const start = Date.now();
|
|
488
|
+
let delay = 200;
|
|
489
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
490
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
491
|
+
if (await connectToSocket()) break;
|
|
492
|
+
delay = Math.min(delay * 2, 3e3);
|
|
493
|
+
}
|
|
494
|
+
if (!_connected) return { error: "Daemon restart failed" };
|
|
495
|
+
const final = await doRequest();
|
|
496
|
+
if (!final.error) _consecutiveFailures = 0;
|
|
497
|
+
return final;
|
|
376
498
|
}
|
|
377
499
|
async function embedViaClient(text, priority = "high") {
|
|
378
500
|
if (!_connected && !await connectEmbedDaemon()) return null;
|
|
379
501
|
_requestCount++;
|
|
380
502
|
if (_requestCount % HEALTH_CHECK_INTERVAL === 0) {
|
|
381
503
|
const health = await pingDaemon();
|
|
382
|
-
if (!health) {
|
|
504
|
+
if (!health && !isDaemonTooYoung()) {
|
|
383
505
|
process.stderr.write(`[exed-client] Periodic health check failed at request ${_requestCount} \u2014 restarting daemon
|
|
384
506
|
`);
|
|
385
507
|
killAndRespawnDaemon();
|
|
386
508
|
const start = Date.now();
|
|
387
|
-
let
|
|
509
|
+
let d = 200;
|
|
388
510
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
389
|
-
await new Promise((r) => setTimeout(r,
|
|
511
|
+
await new Promise((r) => setTimeout(r, d));
|
|
390
512
|
if (await connectToSocket()) break;
|
|
391
|
-
|
|
513
|
+
d = Math.min(d * 2, 3e3);
|
|
392
514
|
}
|
|
393
515
|
if (!_connected) return null;
|
|
394
516
|
}
|
|
395
517
|
}
|
|
396
|
-
const result = await
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
killAndRespawnDaemon();
|
|
402
|
-
const start = Date.now();
|
|
403
|
-
let delay = 200;
|
|
404
|
-
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
405
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
406
|
-
if (await connectToSocket()) break;
|
|
407
|
-
delay = Math.min(delay * 2, 3e3);
|
|
408
|
-
}
|
|
409
|
-
if (!_connected) return null;
|
|
410
|
-
const retry = await sendRequest([text], priority);
|
|
411
|
-
if (!retry.error && retry.vectors?.[0]) return retry.vectors[0];
|
|
412
|
-
process.stderr.write(`[exed-client] Embed retry also failed: ${retry.error ?? "no vector"}
|
|
413
|
-
`);
|
|
414
|
-
}
|
|
415
|
-
return null;
|
|
518
|
+
const result = await retryThenRestart(
|
|
519
|
+
() => sendRequest([text], priority),
|
|
520
|
+
"Embed"
|
|
521
|
+
);
|
|
522
|
+
return !result.error && result.vectors?.[0] ? result.vectors[0] : null;
|
|
416
523
|
}
|
|
417
524
|
async function embedBatchViaClient(texts, priority = "high") {
|
|
418
525
|
if (!_connected && !await connectEmbedDaemon()) return null;
|
|
419
526
|
_requestCount++;
|
|
420
|
-
const result = await
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
killAndRespawnDaemon();
|
|
426
|
-
const start = Date.now();
|
|
427
|
-
let delay = 200;
|
|
428
|
-
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
429
|
-
await new Promise((r) => setTimeout(r, delay));
|
|
430
|
-
if (await connectToSocket()) break;
|
|
431
|
-
delay = Math.min(delay * 2, 3e3);
|
|
432
|
-
}
|
|
433
|
-
if (!_connected) return null;
|
|
434
|
-
const retry = await sendRequest(texts, priority);
|
|
435
|
-
if (!retry.error && retry.vectors) return retry.vectors;
|
|
436
|
-
process.stderr.write(`[exed-client] Batch retry also failed: ${retry.error ?? "no vectors"}
|
|
437
|
-
`);
|
|
438
|
-
}
|
|
439
|
-
return null;
|
|
527
|
+
const result = await retryThenRestart(
|
|
528
|
+
() => sendRequest(texts, priority),
|
|
529
|
+
"Batch embed"
|
|
530
|
+
);
|
|
531
|
+
return !result.error && result.vectors ? result.vectors : null;
|
|
440
532
|
}
|
|
441
533
|
function disconnectClient() {
|
|
442
534
|
if (_socket) {
|
|
@@ -454,6 +546,17 @@ function disconnectClient() {
|
|
|
454
546
|
function isClientConnected() {
|
|
455
547
|
return _connected;
|
|
456
548
|
}
|
|
549
|
+
function sendIngestRequest(payload) {
|
|
550
|
+
if (!_socket || !_connected) return false;
|
|
551
|
+
try {
|
|
552
|
+
const id = randomUUID();
|
|
553
|
+
const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
|
|
554
|
+
_socket.write(JSON.stringify({ id, token, type: "ingest", ...payload }) + "\n");
|
|
555
|
+
return true;
|
|
556
|
+
} catch {
|
|
557
|
+
return false;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
457
560
|
export {
|
|
458
561
|
connectEmbedDaemon,
|
|
459
562
|
disconnectClient,
|
|
@@ -461,5 +564,6 @@ export {
|
|
|
461
564
|
embedViaClient,
|
|
462
565
|
isClientConnected,
|
|
463
566
|
pingDaemon,
|
|
464
|
-
sendDaemonRequest
|
|
567
|
+
sendDaemonRequest,
|
|
568
|
+
sendIngestRequest
|
|
465
569
|
};
|