@joshuaswarren/openclaw-engram 9.0.75 → 9.0.77
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/index.js +106 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6697,6 +6697,16 @@ ${stderr}`.split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
|
6697
6697
|
supportsExplainTraces() {
|
|
6698
6698
|
return versionAtLeast(parseQmdVersion(this.cliVersion), [1, 1, 2]);
|
|
6699
6699
|
}
|
|
6700
|
+
/**
|
|
6701
|
+
* QMD v2 (>= 2.0.0) uses a new MCP tool API:
|
|
6702
|
+
* - `search` and `vsearch` tools removed; only `query` tool exists
|
|
6703
|
+
* - `query` accepts `{ searches: [{ type, query }], collections?: string[] }`
|
|
6704
|
+
* instead of `{ query: string, collection?: string }`
|
|
6705
|
+
* - `collection` (singular) → `collections` (plural array)
|
|
6706
|
+
*/
|
|
6707
|
+
isQmdV2() {
|
|
6708
|
+
return versionAtLeast(parseQmdVersion(this.cliVersion), [2, 0, 0]);
|
|
6709
|
+
}
|
|
6700
6710
|
resolveSearchOptions(options) {
|
|
6701
6711
|
const normalized = normalizeSearchOptions(options);
|
|
6702
6712
|
if (!normalized) return void 0;
|
|
@@ -6842,29 +6852,43 @@ ${stderr}`.split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
|
6842
6852
|
async searchViaDaemon(query, collection, maxResults, options, signal) {
|
|
6843
6853
|
if (!this.daemonSession || !this.daemonAvailable) return null;
|
|
6844
6854
|
const startedAtMs = Date.now();
|
|
6855
|
+
const v2 = this.isQmdV2();
|
|
6845
6856
|
try {
|
|
6846
|
-
|
|
6847
|
-
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
6853
|
-
|
|
6854
|
-
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
|
|
6857
|
+
let args;
|
|
6858
|
+
if (v2) {
|
|
6859
|
+
const searches = [{ type: "lex", query }];
|
|
6860
|
+
searches.push({ type: "vec", query });
|
|
6861
|
+
args = { searches, limit: maxResults };
|
|
6862
|
+
if (collection) {
|
|
6863
|
+
args.collections = [collection];
|
|
6864
|
+
}
|
|
6865
|
+
if (options?.intent) {
|
|
6866
|
+
args.intent = options.intent;
|
|
6867
|
+
}
|
|
6868
|
+
if (options?.explain === true) {
|
|
6869
|
+
args.explain = true;
|
|
6870
|
+
}
|
|
6871
|
+
} else {
|
|
6872
|
+
args = { query, limit: maxResults };
|
|
6873
|
+
if (collection) {
|
|
6874
|
+
args.collection = collection;
|
|
6875
|
+
}
|
|
6876
|
+
if (options?.intent) {
|
|
6877
|
+
args.intent = options.intent;
|
|
6878
|
+
}
|
|
6879
|
+
if (options?.explain === true) {
|
|
6880
|
+
args.explain = true;
|
|
6881
|
+
}
|
|
6858
6882
|
}
|
|
6859
6883
|
const result = await this.daemonSession.callTool("query", args, QMD_DAEMON_TIMEOUT_MS, signal);
|
|
6860
6884
|
const durationMs = Date.now() - startedAtMs;
|
|
6861
6885
|
if (this.slowLog?.enabled && durationMs >= this.slowLog.thresholdMs) {
|
|
6862
6886
|
log.warn(
|
|
6863
|
-
`SLOW QMD daemon query: durationMs=${durationMs} collection=${collection ?? "global"} maxResults=${maxResults} queryChars=${query.length}`
|
|
6887
|
+
`SLOW QMD daemon query: durationMs=${durationMs} collection=${collection ?? "global"} maxResults=${maxResults} queryChars=${query.length} v2=${v2}`
|
|
6864
6888
|
);
|
|
6865
6889
|
}
|
|
6866
6890
|
const results = parseMcpSearchResult(result, "daemon");
|
|
6867
|
-
log.debug(`QMD daemon search: ${results.length} results in ${durationMs}ms`);
|
|
6891
|
+
log.debug(`QMD daemon search: ${results.length} results in ${durationMs}ms (v2=${v2})`);
|
|
6868
6892
|
this.recordDaemonSuccess();
|
|
6869
6893
|
return results;
|
|
6870
6894
|
} catch (err) {
|
|
@@ -6884,16 +6908,31 @@ ${stderr}`.split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
|
6884
6908
|
async bm25SearchViaDaemon(query, collection, maxResults, signal) {
|
|
6885
6909
|
if (!this.daemonSession || !this.daemonAvailable) return null;
|
|
6886
6910
|
const startedAtMs = Date.now();
|
|
6911
|
+
const v2 = this.isQmdV2();
|
|
6887
6912
|
try {
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6913
|
+
let result;
|
|
6914
|
+
if (v2) {
|
|
6915
|
+
result = await this.daemonSession.callTool(
|
|
6916
|
+
"query",
|
|
6917
|
+
{
|
|
6918
|
+
searches: [{ type: "lex", query }],
|
|
6919
|
+
collections: [collection],
|
|
6920
|
+
limit: maxResults
|
|
6921
|
+
},
|
|
6922
|
+
QMD_DAEMON_TIMEOUT_MS,
|
|
6923
|
+
signal
|
|
6924
|
+
);
|
|
6925
|
+
} else {
|
|
6926
|
+
result = await this.daemonSession.callTool(
|
|
6927
|
+
"search",
|
|
6928
|
+
{ query, limit: maxResults, collection },
|
|
6929
|
+
QMD_DAEMON_TIMEOUT_MS,
|
|
6930
|
+
signal
|
|
6931
|
+
);
|
|
6932
|
+
}
|
|
6894
6933
|
const durationMs = Date.now() - startedAtMs;
|
|
6895
6934
|
const results = parseMcpSearchResult(result);
|
|
6896
|
-
log.debug(`QMD daemon bm25: ${results.length} results in ${durationMs}ms`);
|
|
6935
|
+
log.debug(`QMD daemon bm25: ${results.length} results in ${durationMs}ms (v2=${v2})`);
|
|
6897
6936
|
this.recordDaemonSuccess();
|
|
6898
6937
|
return results;
|
|
6899
6938
|
} catch (err) {
|
|
@@ -6913,16 +6952,31 @@ ${stderr}`.split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
|
6913
6952
|
async vsearchViaDaemon(query, collection, maxResults, signal) {
|
|
6914
6953
|
if (!this.daemonSession || !this.daemonAvailable) return null;
|
|
6915
6954
|
const startedAtMs = Date.now();
|
|
6955
|
+
const v2 = this.isQmdV2();
|
|
6916
6956
|
try {
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6957
|
+
let result;
|
|
6958
|
+
if (v2) {
|
|
6959
|
+
result = await this.daemonSession.callTool(
|
|
6960
|
+
"query",
|
|
6961
|
+
{
|
|
6962
|
+
searches: [{ type: "vec", query }],
|
|
6963
|
+
collections: [collection],
|
|
6964
|
+
limit: maxResults
|
|
6965
|
+
},
|
|
6966
|
+
QMD_DAEMON_TIMEOUT_MS,
|
|
6967
|
+
signal
|
|
6968
|
+
);
|
|
6969
|
+
} else {
|
|
6970
|
+
result = await this.daemonSession.callTool(
|
|
6971
|
+
"vsearch",
|
|
6972
|
+
{ query, limit: maxResults, collection },
|
|
6973
|
+
QMD_DAEMON_TIMEOUT_MS,
|
|
6974
|
+
signal
|
|
6975
|
+
);
|
|
6976
|
+
}
|
|
6923
6977
|
const durationMs = Date.now() - startedAtMs;
|
|
6924
6978
|
const results = parseMcpSearchResult(result);
|
|
6925
|
-
log.debug(`QMD daemon vsearch: ${results.length} results in ${durationMs}ms`);
|
|
6979
|
+
log.debug(`QMD daemon vsearch: ${results.length} results in ${durationMs}ms (v2=${v2})`);
|
|
6926
6980
|
this.recordDaemonSuccess();
|
|
6927
6981
|
return results;
|
|
6928
6982
|
} catch (err) {
|
|
@@ -39896,7 +39950,7 @@ import path69 from "path";
|
|
|
39896
39950
|
import os6 from "os";
|
|
39897
39951
|
|
|
39898
39952
|
// src/opik-exporter.ts
|
|
39899
|
-
import { createHash as createHash13,
|
|
39953
|
+
import { createHash as createHash13, randomBytes } from "crypto";
|
|
39900
39954
|
import { readFileSync as readFileSync4 } from "fs";
|
|
39901
39955
|
import os5 from "os";
|
|
39902
39956
|
import path68 from "path";
|
|
@@ -39919,6 +39973,20 @@ function readOpikOpenclawConfig(log2) {
|
|
|
39919
39973
|
return {};
|
|
39920
39974
|
}
|
|
39921
39975
|
}
|
|
39976
|
+
function uuidV7() {
|
|
39977
|
+
const now = Date.now();
|
|
39978
|
+
const bytes = randomBytes(16);
|
|
39979
|
+
bytes[0] = now / 2 ** 40 & 255;
|
|
39980
|
+
bytes[1] = now / 2 ** 32 & 255;
|
|
39981
|
+
bytes[2] = now / 2 ** 24 & 255;
|
|
39982
|
+
bytes[3] = now / 2 ** 16 & 255;
|
|
39983
|
+
bytes[4] = now / 2 ** 8 & 255;
|
|
39984
|
+
bytes[5] = now & 255;
|
|
39985
|
+
bytes[6] = bytes[6] & 15 | 112;
|
|
39986
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
39987
|
+
const hex = bytes.toString("hex");
|
|
39988
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
39989
|
+
}
|
|
39922
39990
|
function buildHeaders(cfg) {
|
|
39923
39991
|
const headers = { "Content-Type": "application/json" };
|
|
39924
39992
|
if (cfg.workspaceName) headers["Comet-Workspace"] = cfg.workspaceName;
|
|
@@ -40049,8 +40117,8 @@ var OpikExporter = class _OpikExporter {
|
|
|
40049
40117
|
}
|
|
40050
40118
|
if (evt.timings) metadata.timings = evt.timings;
|
|
40051
40119
|
const span = {
|
|
40052
|
-
id:
|
|
40053
|
-
trace_id: evt.sessionKey ? this.sessionToTraceId(evt.sessionKey) :
|
|
40120
|
+
id: uuidV7(),
|
|
40121
|
+
trace_id: evt.sessionKey ? this.sessionToTraceId(evt.sessionKey) : uuidV7(),
|
|
40054
40122
|
project_name: this.cfg.projectName,
|
|
40055
40123
|
name: "engram:recall",
|
|
40056
40124
|
type: "general",
|
|
@@ -40095,8 +40163,8 @@ var OpikExporter = class _OpikExporter {
|
|
|
40095
40163
|
if (evt.tokenUsage?.output != null) usage.completion_tokens = evt.tokenUsage.output;
|
|
40096
40164
|
if (evt.tokenUsage?.total != null) usage.total_tokens = evt.tokenUsage.total;
|
|
40097
40165
|
const span = {
|
|
40098
|
-
id: state?.spanId ??
|
|
40099
|
-
trace_id: state?.traceId ??
|
|
40166
|
+
id: state?.spanId ?? uuidV7(),
|
|
40167
|
+
trace_id: state?.traceId ?? uuidV7(),
|
|
40100
40168
|
project_name: this.cfg.projectName,
|
|
40101
40169
|
name: `engram:${evt.operation}`,
|
|
40102
40170
|
type: "llm",
|
|
@@ -40119,13 +40187,15 @@ var OpikExporter = class _OpikExporter {
|
|
|
40119
40187
|
// Helpers
|
|
40120
40188
|
// -------------------------------------------------------------------------
|
|
40121
40189
|
/**
|
|
40122
|
-
* Convert a sessionKey to a stable UUID
|
|
40190
|
+
* Convert a sessionKey to a stable, deterministic UUID v7-shaped ID so that
|
|
40123
40191
|
* spans for the same session share a trace_id and are threaded in Opik.
|
|
40124
|
-
* Uses SHA-256
|
|
40192
|
+
* Uses SHA-256 for collision resistance. The timestamp bytes (0-5) come from
|
|
40193
|
+
* the hash itself — they don't reflect real time, but Opik only validates
|
|
40194
|
+
* the version/variant bits, not timestamp ordering.
|
|
40125
40195
|
*/
|
|
40126
40196
|
sessionToTraceId(sessionKey) {
|
|
40127
40197
|
const digest = createHash13("sha256").update(sessionKey).digest();
|
|
40128
|
-
digest[6] = digest[6] & 15 |
|
|
40198
|
+
digest[6] = digest[6] & 15 | 112;
|
|
40129
40199
|
digest[8] = digest[8] & 63 | 128;
|
|
40130
40200
|
const hex = digest.slice(0, 16).toString("hex");
|
|
40131
40201
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|