@deeplake/hivemind 0.7.31 → 0.7.33

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.
@@ -17,21 +17,21 @@ __export(index_marker_store_exports, {
17
17
  hasFreshIndexMarker: () => hasFreshIndexMarker,
18
18
  writeIndexMarker: () => writeIndexMarker
19
19
  });
20
- import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
21
- import { join as join4 } from "node:path";
20
+ import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
21
+ import { join as join5 } from "node:path";
22
22
  import { tmpdir } from "node:os";
23
23
  function getIndexMarkerDir() {
24
- return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join4(tmpdir(), "hivemind-deeplake-indexes");
24
+ return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join5(tmpdir(), "hivemind-deeplake-indexes");
25
25
  }
26
26
  function buildIndexMarkerPath(workspaceId, orgId, table, suffix) {
27
27
  const markerKey = [workspaceId, orgId, table, suffix].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
28
- return join4(getIndexMarkerDir(), `${markerKey}.json`);
28
+ return join5(getIndexMarkerDir(), `${markerKey}.json`);
29
29
  }
30
30
  function hasFreshIndexMarker(markerPath) {
31
31
  if (!existsSync2(markerPath))
32
32
  return false;
33
33
  try {
34
- const raw = JSON.parse(readFileSync3(markerPath, "utf-8"));
34
+ const raw = JSON.parse(readFileSync4(markerPath, "utf-8"));
35
35
  const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
36
36
  if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
37
37
  return false;
@@ -41,8 +41,8 @@ function hasFreshIndexMarker(markerPath) {
41
41
  }
42
42
  }
43
43
  function writeIndexMarker(markerPath) {
44
- mkdirSync2(getIndexMarkerDir(), { recursive: true });
45
- writeFileSync2(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
44
+ mkdirSync3(getIndexMarkerDir(), { recursive: true });
45
+ writeFileSync3(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
46
46
  }
47
47
  var INDEX_MARKER_TTL_MS;
48
48
  var init_index_marker_store = __esm({
@@ -337,6 +337,107 @@ function sqlIdent(name) {
337
337
  var SUMMARY_EMBEDDING_COL = "summary_embedding";
338
338
  var MESSAGE_EMBEDDING_COL = "message_embedding";
339
339
 
340
+ // dist/src/notifications/queue.js
341
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync, mkdirSync as mkdirSync2, openSync, closeSync, unlinkSync as unlinkSync2, statSync } from "node:fs";
342
+ import { join as join4, resolve } from "node:path";
343
+ import { homedir as homedir4 } from "node:os";
344
+ import { setTimeout as sleep } from "node:timers/promises";
345
+ var log2 = (msg) => log("notifications-queue", msg);
346
+ var LOCK_RETRY_MAX = 50;
347
+ var LOCK_RETRY_BASE_MS = 5;
348
+ var LOCK_STALE_MS = 5e3;
349
+ function queuePath() {
350
+ return join4(homedir4(), ".deeplake", "notifications-queue.json");
351
+ }
352
+ function lockPath() {
353
+ return `${queuePath()}.lock`;
354
+ }
355
+ function readQueue() {
356
+ try {
357
+ const raw = readFileSync3(queuePath(), "utf-8");
358
+ const parsed = JSON.parse(raw);
359
+ if (!parsed || !Array.isArray(parsed.queue)) {
360
+ log2(`queue malformed \u2192 treating as empty`);
361
+ return { queue: [] };
362
+ }
363
+ return { queue: parsed.queue };
364
+ } catch {
365
+ return { queue: [] };
366
+ }
367
+ }
368
+ function _isQueuePathInsideHome(path, home) {
369
+ const r = resolve(path);
370
+ const h = resolve(home);
371
+ return r.startsWith(h + "/") || r === h;
372
+ }
373
+ function writeQueue(q) {
374
+ const path = queuePath();
375
+ const home = resolve(homedir4());
376
+ if (!_isQueuePathInsideHome(path, home)) {
377
+ throw new Error(`notifications-queue write blocked: ${path} is outside ${home}`);
378
+ }
379
+ mkdirSync2(join4(home, ".deeplake"), { recursive: true, mode: 448 });
380
+ const tmp = `${path}.${process.pid}.tmp`;
381
+ writeFileSync2(tmp, JSON.stringify(q, null, 2), { mode: 384 });
382
+ renameSync(tmp, path);
383
+ }
384
+ async function withQueueLock(fn) {
385
+ const path = lockPath();
386
+ mkdirSync2(join4(homedir4(), ".deeplake"), { recursive: true, mode: 448 });
387
+ let fd = null;
388
+ for (let attempt = 0; attempt < LOCK_RETRY_MAX; attempt++) {
389
+ try {
390
+ fd = openSync(path, "wx", 384);
391
+ break;
392
+ } catch (e) {
393
+ const code = e.code;
394
+ if (code !== "EEXIST")
395
+ throw e;
396
+ try {
397
+ const age = Date.now() - statSync(path).mtimeMs;
398
+ if (age > LOCK_STALE_MS) {
399
+ unlinkSync2(path);
400
+ continue;
401
+ }
402
+ } catch {
403
+ }
404
+ const delay = LOCK_RETRY_BASE_MS * (attempt + 1);
405
+ await sleep(delay);
406
+ }
407
+ }
408
+ if (fd === null) {
409
+ log2(`lock acquisition gave up after ${LOCK_RETRY_MAX} attempts \u2014 proceeding unlocked (last-writer-wins)`);
410
+ return fn();
411
+ }
412
+ try {
413
+ return fn();
414
+ } finally {
415
+ try {
416
+ closeSync(fd);
417
+ } catch {
418
+ }
419
+ try {
420
+ unlinkSync2(path);
421
+ } catch {
422
+ }
423
+ }
424
+ }
425
+ function sameDedupKey(a, b) {
426
+ if (a.id !== b.id)
427
+ return false;
428
+ return JSON.stringify(a.dedupKey) === JSON.stringify(b.dedupKey);
429
+ }
430
+ async function enqueueNotification(n) {
431
+ await withQueueLock(() => {
432
+ const q = readQueue();
433
+ if (q.queue.some((existing) => sameDedupKey(existing, n))) {
434
+ return;
435
+ }
436
+ q.queue.push(n);
437
+ writeQueue(q);
438
+ });
439
+ }
440
+
340
441
  // dist/src/deeplake-api.js
341
442
  var indexMarkerStorePromise = null;
342
443
  function getIndexMarkerStore() {
@@ -344,7 +445,7 @@ function getIndexMarkerStore() {
344
445
  indexMarkerStorePromise = Promise.resolve().then(() => (init_index_marker_store(), index_marker_store_exports));
345
446
  return indexMarkerStorePromise;
346
447
  }
347
- var log2 = (msg) => log("sdk", msg);
448
+ var log3 = (msg) => log("sdk", msg);
348
449
  function summarizeSql(sql, maxLen = 220) {
349
450
  const compact = sql.replace(/\s+/g, " ").trim();
350
451
  return compact.length > maxLen ? `${compact.slice(0, maxLen)}...` : compact;
@@ -356,7 +457,38 @@ function traceSql(msg) {
356
457
  process.stderr.write(`[deeplake-sql] ${msg}
357
458
  `);
358
459
  if (process.env.HIVEMIND_DEBUG === "1")
359
- log2(msg);
460
+ log3(msg);
461
+ }
462
+ var _signalledBalanceExhausted = false;
463
+ function maybeSignalBalanceExhausted(status, bodyText) {
464
+ if (status !== 402)
465
+ return;
466
+ if (!bodyText.includes("balance_cents"))
467
+ return;
468
+ if (_signalledBalanceExhausted)
469
+ return;
470
+ _signalledBalanceExhausted = true;
471
+ log3(`balance exhausted \u2014 enqueuing session-start banner (body=${bodyText.slice(0, 120)})`);
472
+ enqueueNotification({
473
+ id: "balance-exhausted",
474
+ severity: "warn",
475
+ transient: true,
476
+ title: "Hivemind credits exhausted \u2014 top up to keep capturing",
477
+ body: `Sessions are not being saved and memory recall is returning empty. Top up at ${billingUrl()} to restore capture and recall.`,
478
+ dedupKey: { reason: "balance-zero" }
479
+ }).catch((e) => {
480
+ log3(`enqueue balance-exhausted failed: ${e instanceof Error ? e.message : String(e)}`);
481
+ });
482
+ }
483
+ function billingUrl() {
484
+ try {
485
+ const c = loadCredentials();
486
+ if (c?.orgName && c?.workspaceId) {
487
+ return `https://deeplake.ai/${encodeURIComponent(c.orgName)}/workspace/${encodeURIComponent(c.workspaceId)}/billing`;
488
+ }
489
+ } catch {
490
+ }
491
+ return "https://deeplake.ai";
360
492
  }
361
493
  var RETRYABLE_CODES = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
362
494
  var MAX_RETRIES = 3;
@@ -365,8 +497,8 @@ var MAX_CONCURRENCY = 5;
365
497
  function getQueryTimeoutMs() {
366
498
  return Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
367
499
  }
368
- function sleep(ms) {
369
- return new Promise((resolve) => setTimeout(resolve, ms));
500
+ function sleep2(ms) {
501
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
370
502
  }
371
503
  function isTimeoutError(error) {
372
504
  const name = error instanceof Error ? error.name.toLowerCase() : "";
@@ -396,7 +528,7 @@ var Semaphore = class {
396
528
  this.active++;
397
529
  return;
398
530
  }
399
- await new Promise((resolve) => this.waiting.push(resolve));
531
+ await new Promise((resolve2) => this.waiting.push(resolve2));
400
532
  }
401
533
  release() {
402
534
  this.active--;
@@ -467,8 +599,8 @@ var DeeplakeApi = class {
467
599
  lastError = e instanceof Error ? e : new Error(String(e));
468
600
  if (attempt < MAX_RETRIES) {
469
601
  const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
470
- log2(`query retry ${attempt + 1}/${MAX_RETRIES} (fetch error: ${lastError.message}) in ${delay.toFixed(0)}ms`);
471
- await sleep(delay);
602
+ log3(`query retry ${attempt + 1}/${MAX_RETRIES} (fetch error: ${lastError.message}) in ${delay.toFixed(0)}ms`);
603
+ await sleep2(delay);
472
604
  continue;
473
605
  }
474
606
  throw lastError;
@@ -484,10 +616,11 @@ var DeeplakeApi = class {
484
616
  const alreadyExists = resp.status === 500 && isDuplicateIndexError(text);
485
617
  if (!alreadyExists && attempt < MAX_RETRIES && (RETRYABLE_CODES.has(resp.status) || retryable403)) {
486
618
  const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
487
- log2(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
488
- await sleep(delay);
619
+ log3(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
620
+ await sleep2(delay);
489
621
  continue;
490
622
  }
623
+ maybeSignalBalanceExhausted(resp.status, text);
491
624
  throw new Error(`Query failed: ${resp.status}: ${text.slice(0, 200)}`);
492
625
  }
493
626
  throw lastError ?? new Error("Query failed: max retries exceeded");
@@ -508,7 +641,7 @@ var DeeplakeApi = class {
508
641
  const chunk = rows.slice(i, i + CONCURRENCY);
509
642
  await Promise.allSettled(chunk.map((r) => this.upsertRowSql(r)));
510
643
  }
511
- log2(`commit: ${rows.length} rows`);
644
+ log3(`commit: ${rows.length} rows`);
512
645
  }
513
646
  async upsertRowSql(row) {
514
647
  const ts = (/* @__PURE__ */ new Date()).toISOString();
@@ -564,7 +697,7 @@ var DeeplakeApi = class {
564
697
  markers.writeIndexMarker(markerPath);
565
698
  return;
566
699
  }
567
- log2(`index "${indexName}" skipped: ${e.message}`);
700
+ log3(`index "${indexName}" skipped: ${e.message}`);
568
701
  }
569
702
  }
570
703
  /**
@@ -654,13 +787,13 @@ var DeeplakeApi = class {
654
787
  };
655
788
  }
656
789
  if (attempt < MAX_RETRIES && RETRYABLE_CODES.has(resp.status)) {
657
- await sleep(BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200);
790
+ await sleep2(BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200);
658
791
  continue;
659
792
  }
660
793
  return { tables: [], cacheable: false };
661
794
  } catch {
662
795
  if (attempt < MAX_RETRIES) {
663
- await sleep(BASE_DELAY_MS * Math.pow(2, attempt));
796
+ await sleep2(BASE_DELAY_MS * Math.pow(2, attempt));
664
797
  continue;
665
798
  }
666
799
  return { tables: [], cacheable: false };
@@ -688,9 +821,9 @@ var DeeplakeApi = class {
688
821
  } catch (err) {
689
822
  lastErr = err;
690
823
  const msg = err instanceof Error ? err.message : String(err);
691
- log2(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
824
+ log3(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
692
825
  if (attempt < OUTER_BACKOFFS_MS.length) {
693
- await sleep(OUTER_BACKOFFS_MS[attempt]);
826
+ await sleep2(OUTER_BACKOFFS_MS[attempt]);
694
827
  }
695
828
  }
696
829
  }
@@ -701,9 +834,9 @@ var DeeplakeApi = class {
701
834
  const tbl = sqlIdent(name ?? this.tableName);
702
835
  const tables = await this.listTables();
703
836
  if (!tables.includes(tbl)) {
704
- log2(`table "${tbl}" not found, creating`);
837
+ log3(`table "${tbl}" not found, creating`);
705
838
  await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${tbl}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', summary TEXT NOT NULL DEFAULT '', summary_embedding FLOAT4[], author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'text/plain', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', plugin_version TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, tbl);
706
- log2(`table "${tbl}" created`);
839
+ log3(`table "${tbl}" created`);
707
840
  if (!tables.includes(tbl))
708
841
  this._tablesCache = [...tables, tbl];
709
842
  }
@@ -716,9 +849,9 @@ var DeeplakeApi = class {
716
849
  const safe = sqlIdent(name);
717
850
  const tables = await this.listTables();
718
851
  if (!tables.includes(safe)) {
719
- log2(`table "${safe}" not found, creating`);
852
+ log3(`table "${safe}" not found, creating`);
720
853
  await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${safe}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', message JSONB, message_embedding FLOAT4[], author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'application/json', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', plugin_version TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, safe);
721
- log2(`table "${safe}" created`);
854
+ log3(`table "${safe}" created`);
722
855
  if (!tables.includes(safe))
723
856
  this._tablesCache = [...tables, safe];
724
857
  }
@@ -741,9 +874,9 @@ var DeeplakeApi = class {
741
874
  const safe = sqlIdent(name);
742
875
  const tables = await this.listTables();
743
876
  if (!tables.includes(safe)) {
744
- log2(`table "${safe}" not found, creating`);
877
+ log3(`table "${safe}" not found, creating`);
745
878
  await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${safe}" (id TEXT NOT NULL DEFAULT '', name TEXT NOT NULL DEFAULT '', project TEXT NOT NULL DEFAULT '', project_key TEXT NOT NULL DEFAULT '', local_path TEXT NOT NULL DEFAULT '', install TEXT NOT NULL DEFAULT 'project', source_sessions TEXT NOT NULL DEFAULT '[]', source_agent TEXT NOT NULL DEFAULT '', scope TEXT NOT NULL DEFAULT 'me', author TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', trigger_text TEXT NOT NULL DEFAULT '', body TEXT NOT NULL DEFAULT '', version BIGINT NOT NULL DEFAULT 1, created_at TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL DEFAULT '') USING deeplake`, safe);
746
- log2(`table "${safe}" created`);
879
+ log3(`table "${safe}" created`);
747
880
  if (!tables.includes(safe))
748
881
  this._tablesCache = [...tables, safe];
749
882
  }
@@ -774,10 +907,10 @@ function parseArgs(argv) {
774
907
  }
775
908
  function confirm(message) {
776
909
  const rl = createInterface({ input: process.stdin, output: process.stderr });
777
- return new Promise((resolve) => {
910
+ return new Promise((resolve2) => {
778
911
  rl.question(`${message} [y/N] `, (answer) => {
779
912
  rl.close();
780
- resolve(answer.trim().toLowerCase() === "y");
913
+ resolve2(answer.trim().toLowerCase() === "y");
781
914
  });
782
915
  });
783
916
  }
@@ -4,7 +4,14 @@
4
4
  import { createServer } from "node:net";
5
5
  import { unlinkSync, writeFileSync, existsSync, mkdirSync, chmodSync } from "node:fs";
6
6
 
7
+ // dist/src/embeddings/nomic.js
8
+ import { createRequire } from "node:module";
9
+ import { homedir } from "node:os";
10
+ import { join } from "node:path";
11
+ import { pathToFileURL } from "node:url";
12
+
7
13
  // dist/src/embeddings/protocol.js
14
+ var PROTOCOL_VERSION = 1;
8
15
  var DEFAULT_SOCKET_DIR = "/tmp";
9
16
  var DEFAULT_MODEL_REPO = "nomic-ai/nomic-embed-text-v1.5";
10
17
  var DEFAULT_DTYPE = "q8";
@@ -20,6 +27,39 @@ function pidPathFor(uid, dir = DEFAULT_SOCKET_DIR) {
20
27
  }
21
28
 
22
29
  // dist/src/embeddings/nomic.js
30
+ async function _importFromCanonicalSharedDeps(sharedDir = join(homedir(), ".hivemind", "embed-deps")) {
31
+ const base = pathToFileURL(`${sharedDir}/`).href;
32
+ const absMain = createRequire(base).resolve("@huggingface/transformers");
33
+ const mod = await import(pathToFileURL(absMain).href);
34
+ return _normalizeTransformersModule(mod);
35
+ }
36
+ async function _importFromBareSpecifier() {
37
+ const mod = await import("@huggingface/transformers");
38
+ return _normalizeTransformersModule(mod);
39
+ }
40
+ function _normalizeTransformersModule(mod) {
41
+ const m = mod;
42
+ if (m.default && typeof m.default === "object" && "pipeline" in m.default) {
43
+ return m.default;
44
+ }
45
+ return m;
46
+ }
47
+ async function defaultImportTransformers(canonical = _importFromCanonicalSharedDeps, bare = _importFromBareSpecifier) {
48
+ let canonicalErr;
49
+ try {
50
+ return await canonical();
51
+ } catch (err) {
52
+ canonicalErr = err;
53
+ }
54
+ try {
55
+ return await bare();
56
+ } catch (bareErr) {
57
+ const detail = bareErr instanceof Error ? bareErr.message : String(bareErr);
58
+ const canonicalDetail = canonicalErr instanceof Error ? canonicalErr.message : String(canonicalErr);
59
+ throw new Error(`@huggingface/transformers is not installed anywhere reachable. Run \`hivemind embeddings install\` to install it. (canonical: ${canonicalDetail}; bare: ${detail})`);
60
+ }
61
+ }
62
+ var _importTransformers = defaultImportTransformers;
23
63
  var NomicEmbedder = class {
24
64
  pipeline = null;
25
65
  loading = null;
@@ -37,7 +77,7 @@ var NomicEmbedder = class {
37
77
  if (this.loading)
38
78
  return this.loading;
39
79
  this.loading = (async () => {
40
- const mod = await import("@huggingface/transformers");
80
+ const mod = await _importTransformers();
41
81
  mod.env.allowLocalModels = false;
42
82
  mod.env.useFSCache = true;
43
83
  this.pipeline = await mod.pipeline("feature-extraction", this.repo, { dtype: this.dtype });
@@ -94,9 +134,9 @@ var NomicEmbedder = class {
94
134
 
95
135
  // dist/src/utils/debug.js
96
136
  import { appendFileSync } from "node:fs";
97
- import { join } from "node:path";
98
- import { homedir } from "node:os";
99
- var LOG = join(homedir(), ".deeplake", "hook-debug.log");
137
+ import { join as join2 } from "node:path";
138
+ import { homedir as homedir2 } from "node:os";
139
+ var LOG = join2(homedir2(), ".deeplake", "hook-debug.log");
100
140
  function isDebug() {
101
141
  return process.env.HIVEMIND_DEBUG === "1";
102
142
  }
@@ -120,6 +160,7 @@ var EmbedDaemon = class {
120
160
  pidPath;
121
161
  idleTimeoutMs;
122
162
  idleTimer = null;
163
+ daemonPath;
123
164
  constructor(opts = {}) {
124
165
  const uid = getUid();
125
166
  const dir = opts.socketDir ?? "/tmp";
@@ -127,6 +168,7 @@ var EmbedDaemon = class {
127
168
  this.pidPath = pidPathFor(uid, dir);
128
169
  this.idleTimeoutMs = opts.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
129
170
  this.embedder = new NomicEmbedder({ repo: opts.repo, dtype: opts.dtype, dims: opts.dims });
171
+ this.daemonPath = opts.daemonPath ?? process.argv[1] ?? "";
130
172
  }
131
173
  async start() {
132
174
  mkdirSync(this.socketPath.replace(/\/[^/]+$/, ""), { recursive: true });
@@ -218,6 +260,15 @@ var EmbedDaemon = class {
218
260
  }
219
261
  }
220
262
  async dispatch(req) {
263
+ if (req.op === "hello") {
264
+ const h = req;
265
+ return {
266
+ id: h.id,
267
+ daemonPath: this.daemonPath,
268
+ pid: process.pid,
269
+ protocolVersion: PROTOCOL_VERSION
270
+ };
271
+ }
221
272
  if (req.op === "ping") {
222
273
  const p = req;
223
274
  return { id: p.id, ready: true, model: this.embedder.repo, dims: this.embedder.dims };