@deeplake/hivemind 0.6.47 → 0.7.4
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +158 -51
- package/bundle/cli.js +4103 -282
- package/codex/bundle/capture.js +510 -90
- package/codex/bundle/commands/auth-login.js +219 -72
- package/codex/bundle/embeddings/embed-daemon.js +243 -0
- package/codex/bundle/pre-tool-use.js +713 -108
- package/codex/bundle/session-start-setup.js +209 -58
- package/codex/bundle/session-start.js +40 -11
- package/codex/bundle/shell/deeplake-shell.js +679 -112
- package/codex/bundle/stop.js +477 -59
- package/codex/bundle/wiki-worker.js +312 -11
- package/cursor/bundle/capture.js +768 -57
- package/cursor/bundle/commands/auth-login.js +219 -72
- package/cursor/bundle/embeddings/embed-daemon.js +243 -0
- package/cursor/bundle/pre-tool-use.js +1684 -0
- package/cursor/bundle/session-end.js +223 -2
- package/cursor/bundle/session-start.js +209 -57
- package/cursor/bundle/shell/deeplake-shell.js +679 -112
- package/cursor/bundle/wiki-worker.js +571 -0
- package/hermes/bundle/capture.js +1194 -0
- package/hermes/bundle/commands/auth-login.js +1009 -0
- package/hermes/bundle/embeddings/embed-daemon.js +243 -0
- package/hermes/bundle/package.json +1 -0
- package/hermes/bundle/pre-tool-use.js +1681 -0
- package/hermes/bundle/session-end.js +265 -0
- package/hermes/bundle/session-start.js +655 -0
- package/hermes/bundle/shell/deeplake-shell.js +69905 -0
- package/hermes/bundle/wiki-worker.js +572 -0
- package/mcp/bundle/server.js +289 -69
- package/openclaw/dist/chunks/auth-creds-AEKS6D3P.js +14 -0
- package/openclaw/dist/chunks/chunk-SRCBBT4H.js +37 -0
- package/openclaw/dist/chunks/config-G23NI5TV.js +33 -0
- package/openclaw/dist/chunks/index-marker-store-PGT5CW6T.js +33 -0
- package/openclaw/dist/chunks/setup-config-C35UK4LP.js +114 -0
- package/openclaw/dist/index.js +752 -702
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/package.json +7 -3
- package/pi/extension-source/hivemind.ts +807 -0
|
@@ -1,38 +1,106 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// dist/src/index-marker-store.js
|
|
13
|
+
var index_marker_store_exports = {};
|
|
14
|
+
__export(index_marker_store_exports, {
|
|
15
|
+
buildIndexMarkerPath: () => buildIndexMarkerPath,
|
|
16
|
+
getIndexMarkerDir: () => getIndexMarkerDir,
|
|
17
|
+
hasFreshIndexMarker: () => hasFreshIndexMarker,
|
|
18
|
+
writeIndexMarker: () => writeIndexMarker
|
|
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";
|
|
22
|
+
import { tmpdir } from "node:os";
|
|
23
|
+
function getIndexMarkerDir() {
|
|
24
|
+
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join4(tmpdir(), "hivemind-deeplake-indexes");
|
|
25
|
+
}
|
|
26
|
+
function buildIndexMarkerPath(workspaceId, orgId, table, suffix) {
|
|
27
|
+
const markerKey = [workspaceId, orgId, table, suffix].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
28
|
+
return join4(getIndexMarkerDir(), `${markerKey}.json`);
|
|
29
|
+
}
|
|
30
|
+
function hasFreshIndexMarker(markerPath) {
|
|
31
|
+
if (!existsSync2(markerPath))
|
|
32
|
+
return false;
|
|
33
|
+
try {
|
|
34
|
+
const raw = JSON.parse(readFileSync3(markerPath, "utf-8"));
|
|
35
|
+
const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
|
|
36
|
+
if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
|
|
37
|
+
return false;
|
|
38
|
+
return true;
|
|
39
|
+
} catch {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function writeIndexMarker(markerPath) {
|
|
44
|
+
mkdirSync2(getIndexMarkerDir(), { recursive: true });
|
|
45
|
+
writeFileSync2(markerPath, JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
46
|
+
}
|
|
47
|
+
var INDEX_MARKER_TTL_MS;
|
|
48
|
+
var init_index_marker_store = __esm({
|
|
49
|
+
"dist/src/index-marker-store.js"() {
|
|
50
|
+
"use strict";
|
|
51
|
+
INDEX_MARKER_TTL_MS = Number(process.env.HIVEMIND_INDEX_MARKER_TTL_MS ?? 6 * 60 * 6e4);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
2
54
|
|
|
3
55
|
// dist/src/commands/auth.js
|
|
4
|
-
import {
|
|
56
|
+
import { execSync } from "node:child_process";
|
|
57
|
+
|
|
58
|
+
// dist/src/utils/client-header.js
|
|
59
|
+
var DEEPLAKE_CLIENT_HEADER = "X-Deeplake-Client";
|
|
60
|
+
function deeplakeClientValue() {
|
|
61
|
+
return "hivemind";
|
|
62
|
+
}
|
|
63
|
+
function deeplakeClientHeader() {
|
|
64
|
+
return { [DEEPLAKE_CLIENT_HEADER]: deeplakeClientValue() };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// dist/src/commands/auth-creds.js
|
|
68
|
+
import { readFileSync, writeFileSync, mkdirSync, unlinkSync } from "node:fs";
|
|
5
69
|
import { join } from "node:path";
|
|
6
70
|
import { homedir } from "node:os";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
71
|
+
function configDir() {
|
|
72
|
+
return join(homedir(), ".deeplake");
|
|
73
|
+
}
|
|
74
|
+
function credsPath() {
|
|
75
|
+
return join(configDir(), "credentials.json");
|
|
76
|
+
}
|
|
11
77
|
function loadCredentials() {
|
|
12
|
-
if (!existsSync(CREDS_PATH))
|
|
13
|
-
return null;
|
|
14
78
|
try {
|
|
15
|
-
return JSON.parse(readFileSync(
|
|
79
|
+
return JSON.parse(readFileSync(credsPath(), "utf-8"));
|
|
16
80
|
} catch {
|
|
17
81
|
return null;
|
|
18
82
|
}
|
|
19
83
|
}
|
|
20
84
|
function saveCredentials(creds) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
writeFileSync(CREDS_PATH, JSON.stringify({ ...creds, savedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), { mode: 384 });
|
|
85
|
+
mkdirSync(configDir(), { recursive: true, mode: 448 });
|
|
86
|
+
writeFileSync(credsPath(), JSON.stringify({ ...creds, savedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2), { mode: 384 });
|
|
24
87
|
}
|
|
25
88
|
function deleteCredentials() {
|
|
26
|
-
|
|
27
|
-
unlinkSync(
|
|
89
|
+
try {
|
|
90
|
+
unlinkSync(credsPath());
|
|
28
91
|
return true;
|
|
92
|
+
} catch {
|
|
93
|
+
return false;
|
|
29
94
|
}
|
|
30
|
-
return false;
|
|
31
95
|
}
|
|
96
|
+
|
|
97
|
+
// dist/src/commands/auth.js
|
|
98
|
+
var DEFAULT_API_URL = "https://api.deeplake.ai";
|
|
32
99
|
async function apiGet(path, token, apiUrl, orgId) {
|
|
33
100
|
const headers = {
|
|
34
101
|
Authorization: `Bearer ${token}`,
|
|
35
|
-
"Content-Type": "application/json"
|
|
102
|
+
"Content-Type": "application/json",
|
|
103
|
+
...deeplakeClientHeader()
|
|
36
104
|
};
|
|
37
105
|
if (orgId)
|
|
38
106
|
headers["X-Activeloop-Org-Id"] = orgId;
|
|
@@ -44,7 +112,8 @@ async function apiGet(path, token, apiUrl, orgId) {
|
|
|
44
112
|
async function apiPost(path, body, token, apiUrl, orgId) {
|
|
45
113
|
const headers = {
|
|
46
114
|
Authorization: `Bearer ${token}`,
|
|
47
|
-
"Content-Type": "application/json"
|
|
115
|
+
"Content-Type": "application/json",
|
|
116
|
+
...deeplakeClientHeader()
|
|
48
117
|
};
|
|
49
118
|
if (orgId)
|
|
50
119
|
headers["X-Activeloop-Org-Id"] = orgId;
|
|
@@ -56,7 +125,8 @@ async function apiPost(path, body, token, apiUrl, orgId) {
|
|
|
56
125
|
async function apiDelete(path, token, apiUrl, orgId) {
|
|
57
126
|
const headers = {
|
|
58
127
|
Authorization: `Bearer ${token}`,
|
|
59
|
-
"Content-Type": "application/json"
|
|
128
|
+
"Content-Type": "application/json",
|
|
129
|
+
...deeplakeClientHeader()
|
|
60
130
|
};
|
|
61
131
|
if (orgId)
|
|
62
132
|
headers["X-Activeloop-Org-Id"] = orgId;
|
|
@@ -67,7 +137,7 @@ async function apiDelete(path, token, apiUrl, orgId) {
|
|
|
67
137
|
async function requestDeviceCode(apiUrl = DEFAULT_API_URL) {
|
|
68
138
|
const resp = await fetch(`${apiUrl}/auth/device/code`, {
|
|
69
139
|
method: "POST",
|
|
70
|
-
headers: { "Content-Type": "application/json" }
|
|
140
|
+
headers: { "Content-Type": "application/json", ...deeplakeClientHeader() }
|
|
71
141
|
});
|
|
72
142
|
if (!resp.ok)
|
|
73
143
|
throw new Error(`Device flow unavailable: HTTP ${resp.status}`);
|
|
@@ -76,7 +146,7 @@ async function requestDeviceCode(apiUrl = DEFAULT_API_URL) {
|
|
|
76
146
|
async function pollForToken(deviceCode, apiUrl = DEFAULT_API_URL) {
|
|
77
147
|
const resp = await fetch(`${apiUrl}/auth/device/token`, {
|
|
78
148
|
method: "POST",
|
|
79
|
-
headers: { "Content-Type": "application/json" },
|
|
149
|
+
headers: { "Content-Type": "application/json", ...deeplakeClientHeader() },
|
|
80
150
|
body: JSON.stringify({ device_code: deviceCode })
|
|
81
151
|
});
|
|
82
152
|
if (resp.ok)
|
|
@@ -202,14 +272,14 @@ Using: ${orgName}
|
|
|
202
272
|
}
|
|
203
273
|
|
|
204
274
|
// dist/src/config.js
|
|
205
|
-
import { readFileSync as readFileSync2, existsSync
|
|
275
|
+
import { readFileSync as readFileSync2, existsSync } from "node:fs";
|
|
206
276
|
import { join as join2 } from "node:path";
|
|
207
277
|
import { homedir as homedir2, userInfo } from "node:os";
|
|
208
278
|
function loadConfig() {
|
|
209
279
|
const home = homedir2();
|
|
210
280
|
const credPath = join2(home, ".deeplake", "credentials.json");
|
|
211
281
|
let creds = null;
|
|
212
|
-
if (
|
|
282
|
+
if (existsSync(credPath)) {
|
|
213
283
|
try {
|
|
214
284
|
creds = JSON.parse(readFileSync2(credPath, "utf-8"));
|
|
215
285
|
} catch {
|
|
@@ -235,9 +305,6 @@ function loadConfig() {
|
|
|
235
305
|
|
|
236
306
|
// dist/src/deeplake-api.js
|
|
237
307
|
import { randomUUID } from "node:crypto";
|
|
238
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
239
|
-
import { join as join4 } from "node:path";
|
|
240
|
-
import { tmpdir } from "node:os";
|
|
241
308
|
|
|
242
309
|
// dist/src/utils/debug.js
|
|
243
310
|
import { appendFileSync } from "node:fs";
|
|
@@ -257,7 +324,17 @@ function sqlStr(value) {
|
|
|
257
324
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
258
325
|
}
|
|
259
326
|
|
|
327
|
+
// dist/src/embeddings/columns.js
|
|
328
|
+
var SUMMARY_EMBEDDING_COL = "summary_embedding";
|
|
329
|
+
var MESSAGE_EMBEDDING_COL = "message_embedding";
|
|
330
|
+
|
|
260
331
|
// dist/src/deeplake-api.js
|
|
332
|
+
var indexMarkerStorePromise = null;
|
|
333
|
+
function getIndexMarkerStore() {
|
|
334
|
+
if (!indexMarkerStorePromise)
|
|
335
|
+
indexMarkerStorePromise = Promise.resolve().then(() => (init_index_marker_store(), index_marker_store_exports));
|
|
336
|
+
return indexMarkerStorePromise;
|
|
337
|
+
}
|
|
261
338
|
var log2 = (msg) => log("sdk", msg);
|
|
262
339
|
function summarizeSql(sql, maxLen = 220) {
|
|
263
340
|
const compact = sql.replace(/\s+/g, " ").trim();
|
|
@@ -277,7 +354,6 @@ var MAX_RETRIES = 3;
|
|
|
277
354
|
var BASE_DELAY_MS = 500;
|
|
278
355
|
var MAX_CONCURRENCY = 5;
|
|
279
356
|
var QUERY_TIMEOUT_MS = Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
|
|
280
|
-
var INDEX_MARKER_TTL_MS = Number(process.env.HIVEMIND_INDEX_MARKER_TTL_MS ?? 6 * 60 * 6e4);
|
|
281
357
|
function sleep(ms) {
|
|
282
358
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
283
359
|
}
|
|
@@ -297,9 +373,6 @@ function isTransientHtml403(text) {
|
|
|
297
373
|
const body = text.toLowerCase();
|
|
298
374
|
return body.includes("<html") || body.includes("403 forbidden") || body.includes("cloudflare") || body.includes("nginx");
|
|
299
375
|
}
|
|
300
|
-
function getIndexMarkerDir() {
|
|
301
|
-
return process.env.HIVEMIND_INDEX_MARKER_DIR ?? join4(tmpdir(), "hivemind-deeplake-indexes");
|
|
302
|
-
}
|
|
303
376
|
var Semaphore = class {
|
|
304
377
|
max;
|
|
305
378
|
waiting = [];
|
|
@@ -368,7 +441,8 @@ var DeeplakeApi = class {
|
|
|
368
441
|
headers: {
|
|
369
442
|
Authorization: `Bearer ${this.token}`,
|
|
370
443
|
"Content-Type": "application/json",
|
|
371
|
-
"X-Activeloop-Org-Id": this.orgId
|
|
444
|
+
"X-Activeloop-Org-Id": this.orgId,
|
|
445
|
+
...deeplakeClientHeader()
|
|
372
446
|
},
|
|
373
447
|
signal,
|
|
374
448
|
body: JSON.stringify({ query: sql })
|
|
@@ -395,7 +469,8 @@ var DeeplakeApi = class {
|
|
|
395
469
|
}
|
|
396
470
|
const text = await resp.text().catch(() => "");
|
|
397
471
|
const retryable403 = isSessionInsertQuery(sql) && (resp.status === 401 || resp.status === 403 && (text.length === 0 || isTransientHtml403(text)));
|
|
398
|
-
|
|
472
|
+
const alreadyExists = resp.status === 500 && isDuplicateIndexError(text);
|
|
473
|
+
if (!alreadyExists && attempt < MAX_RETRIES && (RETRYABLE_CODES.has(resp.status) || retryable403)) {
|
|
399
474
|
const delay = BASE_DELAY_MS * Math.pow(2, attempt) + Math.random() * 200;
|
|
400
475
|
log2(`query retry ${attempt + 1}/${MAX_RETRIES} (${resp.status}) in ${delay.toFixed(0)}ms`);
|
|
401
476
|
await sleep(delay);
|
|
@@ -429,7 +504,7 @@ var DeeplakeApi = class {
|
|
|
429
504
|
const lud = row.lastUpdateDate ?? ts;
|
|
430
505
|
const exists = await this.query(`SELECT path FROM "${this.tableName}" WHERE path = '${sqlStr(row.path)}' LIMIT 1`);
|
|
431
506
|
if (exists.length > 0) {
|
|
432
|
-
let setClauses = `summary = E'${sqlStr(row.contentText)}', mime_type = '${sqlStr(row.mimeType)}', size_bytes = ${row.sizeBytes}, last_update_date = '${lud}'`;
|
|
507
|
+
let setClauses = `summary = E'${sqlStr(row.contentText)}', ${SUMMARY_EMBEDDING_COL} = NULL, mime_type = '${sqlStr(row.mimeType)}', size_bytes = ${row.sizeBytes}, last_update_date = '${lud}'`;
|
|
433
508
|
if (row.project !== void 0)
|
|
434
509
|
setClauses += `, project = '${sqlStr(row.project)}'`;
|
|
435
510
|
if (row.description !== void 0)
|
|
@@ -437,8 +512,8 @@ var DeeplakeApi = class {
|
|
|
437
512
|
await this.query(`UPDATE "${this.tableName}" SET ${setClauses} WHERE path = '${sqlStr(row.path)}'`);
|
|
438
513
|
} else {
|
|
439
514
|
const id = randomUUID();
|
|
440
|
-
let cols =
|
|
441
|
-
let vals = `'${id}', '${sqlStr(row.path)}', '${sqlStr(row.filename)}', E'${sqlStr(row.contentText)}', '${sqlStr(row.mimeType)}', ${row.sizeBytes}, '${cd}', '${lud}'`;
|
|
515
|
+
let cols = `id, path, filename, summary, ${SUMMARY_EMBEDDING_COL}, mime_type, size_bytes, creation_date, last_update_date`;
|
|
516
|
+
let vals = `'${id}', '${sqlStr(row.path)}', '${sqlStr(row.filename)}', E'${sqlStr(row.contentText)}', NULL, '${sqlStr(row.mimeType)}', ${row.sizeBytes}, '${cd}', '${lud}'`;
|
|
442
517
|
if (row.project !== void 0) {
|
|
443
518
|
cols += ", project";
|
|
444
519
|
vals += `, '${sqlStr(row.project)}'`;
|
|
@@ -463,48 +538,83 @@ var DeeplakeApi = class {
|
|
|
463
538
|
buildLookupIndexName(table, suffix) {
|
|
464
539
|
return `idx_${table}_${suffix}`.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
465
540
|
}
|
|
466
|
-
getLookupIndexMarkerPath(table, suffix) {
|
|
467
|
-
const markerKey = [
|
|
468
|
-
this.workspaceId,
|
|
469
|
-
this.orgId,
|
|
470
|
-
table,
|
|
471
|
-
suffix
|
|
472
|
-
].join("__").replace(/[^a-zA-Z0-9_.-]/g, "_");
|
|
473
|
-
return join4(getIndexMarkerDir(), `${markerKey}.json`);
|
|
474
|
-
}
|
|
475
|
-
hasFreshLookupIndexMarker(table, suffix) {
|
|
476
|
-
const markerPath = this.getLookupIndexMarkerPath(table, suffix);
|
|
477
|
-
if (!existsSync3(markerPath))
|
|
478
|
-
return false;
|
|
479
|
-
try {
|
|
480
|
-
const raw = JSON.parse(readFileSync3(markerPath, "utf-8"));
|
|
481
|
-
const updatedAt = raw.updatedAt ? new Date(raw.updatedAt).getTime() : NaN;
|
|
482
|
-
if (!Number.isFinite(updatedAt) || Date.now() - updatedAt > INDEX_MARKER_TTL_MS)
|
|
483
|
-
return false;
|
|
484
|
-
return true;
|
|
485
|
-
} catch {
|
|
486
|
-
return false;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
markLookupIndexReady(table, suffix) {
|
|
490
|
-
mkdirSync2(getIndexMarkerDir(), { recursive: true });
|
|
491
|
-
writeFileSync2(this.getLookupIndexMarkerPath(table, suffix), JSON.stringify({ updatedAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf-8");
|
|
492
|
-
}
|
|
493
541
|
async ensureLookupIndex(table, suffix, columnsSql) {
|
|
494
|
-
|
|
542
|
+
const markers = await getIndexMarkerStore();
|
|
543
|
+
const markerPath = markers.buildIndexMarkerPath(this.workspaceId, this.orgId, table, suffix);
|
|
544
|
+
if (markers.hasFreshIndexMarker(markerPath))
|
|
495
545
|
return;
|
|
496
546
|
const indexName = this.buildLookupIndexName(table, suffix);
|
|
497
547
|
try {
|
|
498
548
|
await this.query(`CREATE INDEX IF NOT EXISTS "${indexName}" ON "${table}" ${columnsSql}`);
|
|
499
|
-
|
|
549
|
+
markers.writeIndexMarker(markerPath);
|
|
500
550
|
} catch (e) {
|
|
501
551
|
if (isDuplicateIndexError(e)) {
|
|
502
|
-
|
|
552
|
+
markers.writeIndexMarker(markerPath);
|
|
503
553
|
return;
|
|
504
554
|
}
|
|
505
555
|
log2(`index "${indexName}" skipped: ${e.message}`);
|
|
506
556
|
}
|
|
507
557
|
}
|
|
558
|
+
/**
|
|
559
|
+
* Ensure a vector column exists on the given table.
|
|
560
|
+
*
|
|
561
|
+
* The previous implementation always issued `ALTER TABLE ADD COLUMN IF NOT
|
|
562
|
+
* EXISTS …` on every SessionStart. On a long-running workspace that's
|
|
563
|
+
* already migrated, every call returns 500 "Column already exists" — noisy
|
|
564
|
+
* in the log and a wasted round-trip. Worse, the very first call after the
|
|
565
|
+
* column is genuinely added triggers Deeplake's post-ALTER `vector::at`
|
|
566
|
+
* window (~30s) during which subsequent INSERTs fail; minimising the
|
|
567
|
+
* number of ALTER calls minimises exposure to that window.
|
|
568
|
+
*
|
|
569
|
+
* New flow:
|
|
570
|
+
* 1. Check the local marker file (mirrors ensureLookupIndex). If fresh,
|
|
571
|
+
* return — zero network calls.
|
|
572
|
+
* 2. SELECT 1 FROM information_schema.columns WHERE table_name = T AND
|
|
573
|
+
* column_name = C. Read-only, idempotent, can't tickle the post-ALTER
|
|
574
|
+
* bug. If the column is present → mark + return.
|
|
575
|
+
* 3. Only if step 2 says the column is missing, fall back to ALTER ADD
|
|
576
|
+
* COLUMN IF NOT EXISTS. Mark on success, also mark if Deeplake reports
|
|
577
|
+
* "already exists" (race: another client added it between our SELECT
|
|
578
|
+
* and ALTER).
|
|
579
|
+
*
|
|
580
|
+
* Marker uses the same dir / TTL as ensureLookupIndex so both schema
|
|
581
|
+
* caches share an opt-out (HIVEMIND_INDEX_MARKER_DIR) and a TTL knob.
|
|
582
|
+
*/
|
|
583
|
+
async ensureEmbeddingColumn(table, column) {
|
|
584
|
+
await this.ensureColumn(table, column, "FLOAT4[]");
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Generic marker-gated column migration. Same SELECT-then-ALTER flow as
|
|
588
|
+
* ensureEmbeddingColumn, parameterized by SQL type so it can patch up any
|
|
589
|
+
* column that was added to the schema after the table was originally
|
|
590
|
+
* created. Used today for `summary_embedding`, `message_embedding`, and
|
|
591
|
+
* the `agent` column (added 2026-04-11) — the latter has no fallback if
|
|
592
|
+
* a user upgraded over a pre-2026-04-11 table, so every INSERT fails
|
|
593
|
+
* with `column "agent" does not exist`.
|
|
594
|
+
*/
|
|
595
|
+
async ensureColumn(table, column, sqlType) {
|
|
596
|
+
const markers = await getIndexMarkerStore();
|
|
597
|
+
const markerPath = markers.buildIndexMarkerPath(this.workspaceId, this.orgId, table, `col_${column}`);
|
|
598
|
+
if (markers.hasFreshIndexMarker(markerPath))
|
|
599
|
+
return;
|
|
600
|
+
const colCheck = `SELECT 1 FROM information_schema.columns WHERE table_name = '${sqlStr(table)}' AND column_name = '${sqlStr(column)}' AND table_schema = '${sqlStr(this.workspaceId)}' LIMIT 1`;
|
|
601
|
+
const rows = await this.query(colCheck);
|
|
602
|
+
if (rows.length > 0) {
|
|
603
|
+
markers.writeIndexMarker(markerPath);
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
try {
|
|
607
|
+
await this.query(`ALTER TABLE "${table}" ADD COLUMN ${column} ${sqlType}`);
|
|
608
|
+
} catch (e) {
|
|
609
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
610
|
+
if (!/already exists/i.test(msg))
|
|
611
|
+
throw e;
|
|
612
|
+
const recheck = await this.query(colCheck);
|
|
613
|
+
if (recheck.length === 0)
|
|
614
|
+
throw e;
|
|
615
|
+
}
|
|
616
|
+
markers.writeIndexMarker(markerPath);
|
|
617
|
+
}
|
|
508
618
|
/** List all tables in the workspace (with retry). */
|
|
509
619
|
async listTables(forceRefresh = false) {
|
|
510
620
|
if (!forceRefresh && this._tablesCache)
|
|
@@ -520,7 +630,8 @@ var DeeplakeApi = class {
|
|
|
520
630
|
const resp = await fetch(`${this.apiUrl}/workspaces/${this.workspaceId}/tables`, {
|
|
521
631
|
headers: {
|
|
522
632
|
Authorization: `Bearer ${this.token}`,
|
|
523
|
-
"X-Activeloop-Org-Id": this.orgId
|
|
633
|
+
"X-Activeloop-Org-Id": this.orgId,
|
|
634
|
+
...deeplakeClientHeader()
|
|
524
635
|
}
|
|
525
636
|
});
|
|
526
637
|
if (resp.ok) {
|
|
@@ -545,28 +656,60 @@ var DeeplakeApi = class {
|
|
|
545
656
|
}
|
|
546
657
|
return { tables: [], cacheable: false };
|
|
547
658
|
}
|
|
659
|
+
/**
|
|
660
|
+
* Run a `CREATE TABLE` with an extra outer retry budget. The base
|
|
661
|
+
* `query()` already retries 3 times on fetch errors (~3.5s total), but a
|
|
662
|
+
* failed CREATE is permanent corruption — every subsequent SELECT against
|
|
663
|
+
* the missing table fails. Wrapping in an outer loop with longer backoff
|
|
664
|
+
* (2s, 5s, then 10s) gives us ~17s of reach across transient network
|
|
665
|
+
* blips before giving up. Failures still propagate; getApi() resets its
|
|
666
|
+
* cache on init failure (openclaw plugin) so the next call retries the
|
|
667
|
+
* whole init flow.
|
|
668
|
+
*/
|
|
669
|
+
async createTableWithRetry(sql, label) {
|
|
670
|
+
const OUTER_BACKOFFS_MS = [2e3, 5e3, 1e4];
|
|
671
|
+
let lastErr = null;
|
|
672
|
+
for (let attempt = 0; attempt <= OUTER_BACKOFFS_MS.length; attempt++) {
|
|
673
|
+
try {
|
|
674
|
+
await this.query(sql);
|
|
675
|
+
return;
|
|
676
|
+
} catch (err) {
|
|
677
|
+
lastErr = err;
|
|
678
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
679
|
+
log2(`CREATE TABLE "${label}" attempt ${attempt + 1}/${OUTER_BACKOFFS_MS.length + 1} failed: ${msg}`);
|
|
680
|
+
if (attempt < OUTER_BACKOFFS_MS.length) {
|
|
681
|
+
await sleep(OUTER_BACKOFFS_MS[attempt]);
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
throw lastErr;
|
|
686
|
+
}
|
|
548
687
|
/** Create the memory table if it doesn't already exist. Migrate columns on existing tables. */
|
|
549
688
|
async ensureTable(name) {
|
|
550
689
|
const tbl = name ?? this.tableName;
|
|
551
690
|
const tables = await this.listTables();
|
|
552
691
|
if (!tables.includes(tbl)) {
|
|
553
692
|
log2(`table "${tbl}" not found, creating`);
|
|
554
|
-
await this.
|
|
693
|
+
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 '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, tbl);
|
|
555
694
|
log2(`table "${tbl}" created`);
|
|
556
695
|
if (!tables.includes(tbl))
|
|
557
696
|
this._tablesCache = [...tables, tbl];
|
|
558
697
|
}
|
|
698
|
+
await this.ensureEmbeddingColumn(tbl, SUMMARY_EMBEDDING_COL);
|
|
699
|
+
await this.ensureColumn(tbl, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
559
700
|
}
|
|
560
701
|
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
|
|
561
702
|
async ensureSessionsTable(name) {
|
|
562
703
|
const tables = await this.listTables();
|
|
563
704
|
if (!tables.includes(name)) {
|
|
564
705
|
log2(`table "${name}" not found, creating`);
|
|
565
|
-
await this.
|
|
706
|
+
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${name}" (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 '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, name);
|
|
566
707
|
log2(`table "${name}" created`);
|
|
567
708
|
if (!tables.includes(name))
|
|
568
709
|
this._tablesCache = [...tables, name];
|
|
569
710
|
}
|
|
711
|
+
await this.ensureEmbeddingColumn(name, MESSAGE_EMBEDDING_COL);
|
|
712
|
+
await this.ensureColumn(name, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
570
713
|
await this.ensureLookupIndex(name, "path_creation_date", `("path", "creation_date")`);
|
|
571
714
|
}
|
|
572
715
|
};
|
|
@@ -707,8 +850,7 @@ To delete, use: --all, --before <date>, or --session-id <id>`);
|
|
|
707
850
|
}
|
|
708
851
|
|
|
709
852
|
// dist/src/commands/auth-login.js
|
|
710
|
-
async function
|
|
711
|
-
const args = process.argv.slice(2);
|
|
853
|
+
async function runAuthCommand(args) {
|
|
712
854
|
const cmd = args[0] ?? "whoami";
|
|
713
855
|
const creds = loadCredentials();
|
|
714
856
|
const apiUrl = creds?.apiUrl ?? "https://api.deeplake.ai";
|
|
@@ -856,7 +998,12 @@ async function main() {
|
|
|
856
998
|
console.log("Commands: login, logout, whoami, org list, org switch, workspaces, workspace, sessions prune, invite, members, remove, autoupdate");
|
|
857
999
|
}
|
|
858
1000
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1001
|
+
if (process.argv[1] && process.argv[1].endsWith("auth-login.js")) {
|
|
1002
|
+
runAuthCommand(process.argv.slice(2)).catch((e) => {
|
|
1003
|
+
console.error(e.message);
|
|
1004
|
+
process.exit(1);
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
export {
|
|
1008
|
+
runAuthCommand
|
|
1009
|
+
};
|