memorix 1.7.2 → 1.7.3
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/CHANGELOG.md +27 -1
- package/assets/star-history-dark.svg +4 -4
- package/assets/star-history-light.svg +4 -4
- package/assets/star-history.json +47 -3
- package/dist/cli/index.js +396 -64
- package/dist/index.js +368 -62
- package/dist/maintenance-runner.js +365 -58
- package/dist/media-audio-runner.js +365 -58
- package/dist/media-video-runner.js +365 -58
- package/dist/memcode-runtime/CHANGELOG.md +27 -1
- package/dist/sdk.js +367 -61
- package/dist/vector-backfill-runner.js +365 -58
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/CONFIGURATION.md +57 -1
- package/docs/PERFORMANCE.md +3 -1
- package/docs/SETUP.md +2 -1
- package/package.json +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/config-migrate.ts +7 -0
- package/src/cli/commands/doctor.ts +5 -1
- package/src/cli/commands/init.ts +17 -0
- package/src/cli/commands/status.ts +2 -0
- package/src/config/resolved-config.ts +110 -12
- package/src/config/toml-loader.ts +8 -0
- package/src/config/yaml-loader.ts +9 -0
- package/src/llm/provider.ts +33 -7
- package/src/multimodal/image-loader.ts +6 -3
- package/src/rerank/http-provider.ts +125 -0
- package/src/rerank/index.ts +81 -0
- package/src/rerank/policy.ts +88 -0
- package/src/store/orama-store.ts +79 -53
package/dist/cli/index.js
CHANGED
|
@@ -3232,7 +3232,7 @@ ${import_picocolors.default.gray(m3)} ${s4}
|
|
|
3232
3232
|
|
|
3233
3233
|
// src/cli/version.ts
|
|
3234
3234
|
function getCliVersion() {
|
|
3235
|
-
return true ? "1.7.
|
|
3235
|
+
return true ? "1.7.3" : pkg.version;
|
|
3236
3236
|
}
|
|
3237
3237
|
var init_version = __esm({
|
|
3238
3238
|
"src/cli/version.ts"() {
|
|
@@ -20748,6 +20748,7 @@ function loadYamlConfig(projectRoot) {
|
|
|
20748
20748
|
llm: { ...userConfig.llm, ...projectConfig.llm },
|
|
20749
20749
|
agent: { ...userConfig.agent, ...projectConfig.agent },
|
|
20750
20750
|
embedding: { ...userConfig.embedding, ...projectConfig.embedding },
|
|
20751
|
+
rerank: { ...userConfig.rerank, ...projectConfig.rerank },
|
|
20751
20752
|
git: { ...userConfig.git, ...projectConfig.git },
|
|
20752
20753
|
codegraph: { ...userConfig.codegraph, ...projectConfig.codegraph },
|
|
20753
20754
|
behavior: { ...userConfig.behavior, ...projectConfig.behavior },
|
|
@@ -21024,6 +21025,7 @@ function mergeTomlConfig(base, override) {
|
|
|
21024
21025
|
llm: { ...base.memory?.llm, ...override.memory?.llm }
|
|
21025
21026
|
},
|
|
21026
21027
|
embedding: { ...base.embedding, ...override.embedding },
|
|
21028
|
+
rerank: { ...base.rerank, ...override.rerank },
|
|
21027
21029
|
hooks: { ...base.hooks, ...override.hooks },
|
|
21028
21030
|
git: { ...base.git, ...override.git },
|
|
21029
21031
|
codegraph: { ...base.codegraph, ...override.codegraph },
|
|
@@ -21575,6 +21577,7 @@ __export(resolved_config_exports, {
|
|
|
21575
21577
|
getResolvedConfigForCwd: () => getResolvedConfigForCwd,
|
|
21576
21578
|
getResolvedEmbeddingLane: () => getResolvedEmbeddingLane,
|
|
21577
21579
|
getResolvedMemoryLane: () => getResolvedMemoryLane,
|
|
21580
|
+
getResolvedRerankLane: () => getResolvedRerankLane,
|
|
21578
21581
|
resetResolvedConfigCache: () => resetResolvedConfigCache
|
|
21579
21582
|
});
|
|
21580
21583
|
import { homedir as homedir5 } from "os";
|
|
@@ -21607,6 +21610,16 @@ function getResolvedConfig(options = {}) {
|
|
|
21607
21610
|
legacy.llm?.baseUrl
|
|
21608
21611
|
);
|
|
21609
21612
|
const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
21613
|
+
const memoryLlmApiKey = first(
|
|
21614
|
+
process.env.MEMORIX_LLM_API_KEY,
|
|
21615
|
+
process.env.MEMORIX_API_KEY,
|
|
21616
|
+
toml.memory?.llm?.api_key,
|
|
21617
|
+
yaml.llm?.apiKey,
|
|
21618
|
+
legacy.llm?.apiKey,
|
|
21619
|
+
process.env.OPENAI_API_KEY,
|
|
21620
|
+
process.env.ANTHROPIC_API_KEY,
|
|
21621
|
+
openRouterMemoryLlmApiKey
|
|
21622
|
+
);
|
|
21610
21623
|
const resolved = {
|
|
21611
21624
|
agent: {
|
|
21612
21625
|
provider: first(
|
|
@@ -21647,16 +21660,7 @@ function getResolvedConfig(options = {}) {
|
|
|
21647
21660
|
provider: memoryLlmProvider,
|
|
21648
21661
|
model: memoryLlmModel,
|
|
21649
21662
|
baseUrl: memoryLlmBaseUrl,
|
|
21650
|
-
apiKey:
|
|
21651
|
-
process.env.MEMORIX_LLM_API_KEY,
|
|
21652
|
-
process.env.MEMORIX_API_KEY,
|
|
21653
|
-
toml.memory?.llm?.api_key,
|
|
21654
|
-
yaml.llm?.apiKey,
|
|
21655
|
-
legacy.llm?.apiKey,
|
|
21656
|
-
process.env.OPENAI_API_KEY,
|
|
21657
|
-
process.env.ANTHROPIC_API_KEY,
|
|
21658
|
-
openRouterMemoryLlmApiKey
|
|
21659
|
-
)
|
|
21663
|
+
apiKey: memoryLlmApiKey
|
|
21660
21664
|
}
|
|
21661
21665
|
},
|
|
21662
21666
|
embedding: {
|
|
@@ -21666,6 +21670,12 @@ function getResolvedConfig(options = {}) {
|
|
|
21666
21670
|
apiKey: first(process.env.MEMORIX_EMBEDDING_API_KEY, toml.embedding?.api_key, yaml.embedding?.apiKey, legacy.embeddingApi?.apiKey, openRouterEmbeddingApiKey),
|
|
21667
21671
|
dimensions: firstNumber(parseNumber(process.env.MEMORIX_EMBEDDING_DIMENSIONS), toml.embedding?.dimensions, yaml.embedding?.dimensions, legacy.embeddingApi?.dimensions)
|
|
21668
21672
|
},
|
|
21673
|
+
rerank: resolveRerankLane({
|
|
21674
|
+
toml,
|
|
21675
|
+
yaml,
|
|
21676
|
+
memoryLlmApiKey,
|
|
21677
|
+
memoryLlmBaseUrl
|
|
21678
|
+
}),
|
|
21669
21679
|
git: {
|
|
21670
21680
|
autoHook: firstBool(toml.git?.auto_hook, yaml.git?.autoHook),
|
|
21671
21681
|
ingestOnCommit: firstBool(toml.git?.ingest_on_commit, yaml.git?.ingestOnCommit),
|
|
@@ -21735,6 +21745,9 @@ function getResolvedMemoryLane(options = {}) {
|
|
|
21735
21745
|
function getResolvedEmbeddingLane(options = {}) {
|
|
21736
21746
|
return getResolvedConfig(options).embedding;
|
|
21737
21747
|
}
|
|
21748
|
+
function getResolvedRerankLane(options = {}) {
|
|
21749
|
+
return getResolvedConfig(options).rerank;
|
|
21750
|
+
}
|
|
21738
21751
|
function resetResolvedConfigCache() {
|
|
21739
21752
|
}
|
|
21740
21753
|
function first(...values) {
|
|
@@ -21777,6 +21790,10 @@ function getEnvSourceNames() {
|
|
|
21777
21790
|
"MEMORIX_EMBEDDING_BASE_URL",
|
|
21778
21791
|
"MEMORIX_EMBEDDING_MODEL",
|
|
21779
21792
|
"MEMORIX_EMBEDDING_DIMENSIONS",
|
|
21793
|
+
"MEMORIX_RERANK_PROVIDER",
|
|
21794
|
+
"MEMORIX_RERANK_MODEL",
|
|
21795
|
+
"MEMORIX_RERANK_BASE_URL",
|
|
21796
|
+
"MEMORIX_RERANK_API_KEY",
|
|
21780
21797
|
"MEMORIX_CODEGRAPH_EXTERNAL_CONTEXT",
|
|
21781
21798
|
"MEMORIX_CODEGRAPH_EXTERNAL_COMMAND",
|
|
21782
21799
|
"MEMORIX_CODEGRAPH_EXTERNAL_TIMEOUT_MS",
|
|
@@ -21800,6 +21817,63 @@ function normalizeExternalContext(value) {
|
|
|
21800
21817
|
if (normalized === "auto" || normalized === "off") return normalized;
|
|
21801
21818
|
return void 0;
|
|
21802
21819
|
}
|
|
21820
|
+
function normalizeRerankProvider(value) {
|
|
21821
|
+
const normalized = value?.trim().toLowerCase();
|
|
21822
|
+
if (normalized === "http") return "http";
|
|
21823
|
+
return "off";
|
|
21824
|
+
}
|
|
21825
|
+
function resolveRerankLane(args) {
|
|
21826
|
+
const provider2 = normalizeRerankProvider(first(
|
|
21827
|
+
process.env.MEMORIX_RERANK_PROVIDER,
|
|
21828
|
+
args.toml.rerank?.provider,
|
|
21829
|
+
args.yaml.rerank?.provider,
|
|
21830
|
+
"off"
|
|
21831
|
+
));
|
|
21832
|
+
const model = first(
|
|
21833
|
+
process.env.MEMORIX_RERANK_MODEL,
|
|
21834
|
+
args.toml.rerank?.model,
|
|
21835
|
+
args.yaml.rerank?.model
|
|
21836
|
+
);
|
|
21837
|
+
const explicitBaseUrl = first(
|
|
21838
|
+
process.env.MEMORIX_RERANK_BASE_URL,
|
|
21839
|
+
args.toml.rerank?.base_url,
|
|
21840
|
+
args.yaml.rerank?.baseUrl
|
|
21841
|
+
);
|
|
21842
|
+
const baseUrl = provider2 === "http" ? first(explicitBaseUrl, args.memoryLlmBaseUrl) : explicitBaseUrl;
|
|
21843
|
+
const dedicatedApiKey = first(
|
|
21844
|
+
process.env.MEMORIX_RERANK_API_KEY,
|
|
21845
|
+
args.toml.rerank?.api_key,
|
|
21846
|
+
args.yaml.rerank?.apiKey
|
|
21847
|
+
);
|
|
21848
|
+
const sameEndpoint = provider2 === "http" && sameTrustedEndpoint(baseUrl, args.memoryLlmBaseUrl);
|
|
21849
|
+
const inheritedApiKey = sameEndpoint ? args.memoryLlmApiKey : void 0;
|
|
21850
|
+
const apiKey = first(dedicatedApiKey, inheritedApiKey);
|
|
21851
|
+
const canSendRequest = provider2 === "http" && Boolean(baseUrl) && (Boolean(apiKey) || !args.memoryLlmApiKey || sameEndpoint);
|
|
21852
|
+
return { provider: provider2, model, baseUrl, apiKey, canSendRequest };
|
|
21853
|
+
}
|
|
21854
|
+
function sameTrustedEndpoint(left, right) {
|
|
21855
|
+
const a4 = normalizeTrustedEndpoint(left);
|
|
21856
|
+
const b4 = normalizeTrustedEndpoint(right);
|
|
21857
|
+
return Boolean(a4 && b4 && a4 === b4);
|
|
21858
|
+
}
|
|
21859
|
+
function normalizeTrustedEndpoint(value) {
|
|
21860
|
+
const trimmed = value?.trim();
|
|
21861
|
+
if (!trimmed) return void 0;
|
|
21862
|
+
try {
|
|
21863
|
+
const url2 = new URL(trimmed);
|
|
21864
|
+
const protocol = url2.protocol.toLowerCase();
|
|
21865
|
+
const hostname2 = url2.hostname.toLowerCase();
|
|
21866
|
+
const port = url2.port;
|
|
21867
|
+
let pathname = url2.pathname.replace(/\/+$/, "");
|
|
21868
|
+
if (pathname.toLowerCase().endsWith("/rerank")) {
|
|
21869
|
+
pathname = pathname.slice(0, -"/rerank".length).replace(/\/+$/, "");
|
|
21870
|
+
}
|
|
21871
|
+
return `${protocol}//${hostname2}${port ? `:${port}` : ""}${pathname}`;
|
|
21872
|
+
} catch {
|
|
21873
|
+
const fallback = trimmed.replace(/\/+$/, "").replace(/\/rerank$/i, "").replace(/\/+$/, "");
|
|
21874
|
+
return fallback.toLowerCase() || void 0;
|
|
21875
|
+
}
|
|
21876
|
+
}
|
|
21803
21877
|
var init_resolved_config = __esm({
|
|
21804
21878
|
"src/config/resolved-config.ts"() {
|
|
21805
21879
|
"use strict";
|
|
@@ -24035,9 +24109,27 @@ __export(provider_exports2, {
|
|
|
24035
24109
|
getLLMConfig: () => getLLMConfig,
|
|
24036
24110
|
initLLM: () => initLLM,
|
|
24037
24111
|
isLLMEnabled: () => isLLMEnabled,
|
|
24112
|
+
normalizeOpenAICompatibleBaseUrl: () => normalizeOpenAICompatibleBaseUrl,
|
|
24038
24113
|
parseLLMTimeoutMs: () => parseLLMTimeoutMs,
|
|
24039
24114
|
setLLMConfig: () => setLLMConfig
|
|
24040
24115
|
});
|
|
24116
|
+
function normalizeOpenAICompatibleBaseUrl(baseUrl) {
|
|
24117
|
+
const base = baseUrl.trim().replace(/\/+$/, "");
|
|
24118
|
+
if (!base) return base;
|
|
24119
|
+
let pathname = "";
|
|
24120
|
+
try {
|
|
24121
|
+
pathname = new URL(base).pathname.replace(/\/+$/, "");
|
|
24122
|
+
} catch {
|
|
24123
|
+
pathname = base.split(/[?#]/, 1)[0].replace(/\/+$/, "");
|
|
24124
|
+
}
|
|
24125
|
+
const lastSegment = pathname.split("/").filter(Boolean).at(-1);
|
|
24126
|
+
if (lastSegment && OPENAI_API_VERSION_SEGMENT.test(lastSegment)) {
|
|
24127
|
+
return base;
|
|
24128
|
+
}
|
|
24129
|
+
const queryOrHash = base.match(/[?#].*$/)?.[0] ?? "";
|
|
24130
|
+
const pathWithoutQuery = base.slice(0, base.length - queryOrHash.length).replace(/\/+$/, "");
|
|
24131
|
+
return `${pathWithoutQuery}/v1${queryOrHash}`;
|
|
24132
|
+
}
|
|
24041
24133
|
function parseLLMTimeoutMs(raw) {
|
|
24042
24134
|
if (raw === void 0 || raw.trim() === "") return LLM_TIMEOUT_DEFAULT_MS;
|
|
24043
24135
|
const parsed = Number(raw);
|
|
@@ -24141,8 +24233,7 @@ async function callLLM(systemPrompt, userMessage, signal) {
|
|
|
24141
24233
|
}
|
|
24142
24234
|
async function callOpenAICompatible(systemPrompt, userMessage, signal) {
|
|
24143
24235
|
const config2 = currentConfig;
|
|
24144
|
-
|
|
24145
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
24236
|
+
const base = normalizeOpenAICompatibleBaseUrl(config2.baseUrl);
|
|
24146
24237
|
const url2 = `${base}/chat/completions`;
|
|
24147
24238
|
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
24148
24239
|
const response = await fetch(url2, {
|
|
@@ -24221,8 +24312,7 @@ async function callLLMWithTools(messages, tools, signal) {
|
|
|
24221
24312
|
}
|
|
24222
24313
|
async function callOpenAIWithTools(messages, tools, signal) {
|
|
24223
24314
|
const config2 = currentConfig;
|
|
24224
|
-
|
|
24225
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
24315
|
+
const base = normalizeOpenAICompatibleBaseUrl(config2.baseUrl);
|
|
24226
24316
|
const url2 = `${base}/chat/completions`;
|
|
24227
24317
|
const openaiMessages = messages.map((msg) => {
|
|
24228
24318
|
if (msg.role === "tool") {
|
|
@@ -24372,8 +24462,7 @@ async function callAnthropicWithTools(messages, tools, signal) {
|
|
|
24372
24462
|
}
|
|
24373
24463
|
async function* callOpenAIWithToolsStream(messages, tools) {
|
|
24374
24464
|
const config2 = currentConfig;
|
|
24375
|
-
|
|
24376
|
-
if (!base.endsWith("/v1")) base += "/v1";
|
|
24465
|
+
const base = normalizeOpenAICompatibleBaseUrl(config2.baseUrl);
|
|
24377
24466
|
const url2 = `${base}/chat/completions`;
|
|
24378
24467
|
const openaiMessages = messages.map((msg) => {
|
|
24379
24468
|
if (msg.role === "tool") {
|
|
@@ -24621,7 +24710,7 @@ async function* callAnthropicWithToolsStream(messages, tools) {
|
|
|
24621
24710
|
}
|
|
24622
24711
|
};
|
|
24623
24712
|
}
|
|
24624
|
-
var LLM_TIMEOUT_DEFAULT_MS, LLM_TIMEOUT_MIN_MS, LLM_TIMEOUT_MAX_MS, MAX_LLM_RESPONSE_BYTES, LLM_CALL_TIMEOUT_MS, PROVIDER_DEFAULTS, currentConfig;
|
|
24713
|
+
var LLM_TIMEOUT_DEFAULT_MS, LLM_TIMEOUT_MIN_MS, LLM_TIMEOUT_MAX_MS, MAX_LLM_RESPONSE_BYTES, OPENAI_API_VERSION_SEGMENT, LLM_CALL_TIMEOUT_MS, PROVIDER_DEFAULTS, currentConfig;
|
|
24625
24714
|
var init_provider2 = __esm({
|
|
24626
24715
|
"src/llm/provider.ts"() {
|
|
24627
24716
|
"use strict";
|
|
@@ -24631,6 +24720,7 @@ var init_provider2 = __esm({
|
|
|
24631
24720
|
LLM_TIMEOUT_MIN_MS = 1e3;
|
|
24632
24721
|
LLM_TIMEOUT_MAX_MS = 3e5;
|
|
24633
24722
|
MAX_LLM_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
24723
|
+
OPENAI_API_VERSION_SEGMENT = /^v\d+(?:[a-z][a-z0-9-]*)?$/i;
|
|
24634
24724
|
LLM_CALL_TIMEOUT_MS = parseLLMTimeoutMs(process.env.MEMORIX_LLM_TIMEOUT_MS);
|
|
24635
24725
|
PROVIDER_DEFAULTS = {
|
|
24636
24726
|
openai: { baseUrl: "https://api.openai.com/v1", model: "gpt-4.1-nano" },
|
|
@@ -24690,6 +24780,48 @@ Rules:
|
|
|
24690
24780
|
}
|
|
24691
24781
|
});
|
|
24692
24782
|
|
|
24783
|
+
// src/rerank/policy.ts
|
|
24784
|
+
function parseRerankTimeoutMs(raw) {
|
|
24785
|
+
const value = raw?.trim();
|
|
24786
|
+
if (!value) return DEFAULT_RERANK_TIMEOUT_MS;
|
|
24787
|
+
const parsed = Number(value);
|
|
24788
|
+
if (!Number.isInteger(parsed) || Number.isNaN(parsed)) {
|
|
24789
|
+
console.warn(
|
|
24790
|
+
`[memorix] MEMORIX_RERANK_TIMEOUT_MS="${raw}" is invalid (must be a positive integer between ${RERANK_TIMEOUT_MIN_MS}-${RERANK_TIMEOUT_MAX_MS}ms). Using default ${DEFAULT_RERANK_TIMEOUT_MS}ms.`
|
|
24791
|
+
);
|
|
24792
|
+
return DEFAULT_RERANK_TIMEOUT_MS;
|
|
24793
|
+
}
|
|
24794
|
+
if (parsed < RERANK_TIMEOUT_MIN_MS) return RERANK_TIMEOUT_MIN_MS;
|
|
24795
|
+
if (parsed > RERANK_TIMEOUT_MAX_MS) return RERANK_TIMEOUT_MAX_MS;
|
|
24796
|
+
return parsed;
|
|
24797
|
+
}
|
|
24798
|
+
function resolveRerankTimeoutMs(explicitTimeoutMs) {
|
|
24799
|
+
if (typeof explicitTimeoutMs === "number" && Number.isFinite(explicitTimeoutMs) && explicitTimeoutMs > 0) {
|
|
24800
|
+
return explicitTimeoutMs;
|
|
24801
|
+
}
|
|
24802
|
+
return parseRerankTimeoutMs(process.env.MEMORIX_RERANK_TIMEOUT_MS);
|
|
24803
|
+
}
|
|
24804
|
+
function shouldAttemptHttpRerank(input) {
|
|
24805
|
+
return input.quality === "thorough" && input.hasQuery && input.candidateCount >= MIN_RERANK_CANDIDATES;
|
|
24806
|
+
}
|
|
24807
|
+
function shouldAttemptLlmRerank(input) {
|
|
24808
|
+
if (input.httpRerankConfigured) return false;
|
|
24809
|
+
if (input.quality !== "thorough" || input.tier !== "heavy" || !input.hasQuery) return false;
|
|
24810
|
+
if (input.candidateCount < MIN_RERANK_CANDIDATES) return false;
|
|
24811
|
+
return input.topScore > 0 && input.secondScore / input.topScore > 0.7;
|
|
24812
|
+
}
|
|
24813
|
+
var DEFAULT_RERANK_TIMEOUT_MS, RERANK_TIMEOUT_MIN_MS, RERANK_TIMEOUT_MAX_MS, MIN_RERANK_CANDIDATES;
|
|
24814
|
+
var init_policy = __esm({
|
|
24815
|
+
"src/rerank/policy.ts"() {
|
|
24816
|
+
"use strict";
|
|
24817
|
+
init_esm_shims();
|
|
24818
|
+
DEFAULT_RERANK_TIMEOUT_MS = 3e4;
|
|
24819
|
+
RERANK_TIMEOUT_MIN_MS = 1e3;
|
|
24820
|
+
RERANK_TIMEOUT_MAX_MS = 3e5;
|
|
24821
|
+
MIN_RERANK_CANDIDATES = 3;
|
|
24822
|
+
}
|
|
24823
|
+
});
|
|
24824
|
+
|
|
24693
24825
|
// src/timeout.ts
|
|
24694
24826
|
function withTimeout(promise2, ms2, label) {
|
|
24695
24827
|
return new Promise((resolve6, reject) => {
|
|
@@ -24975,6 +25107,148 @@ var init_aliases = __esm({
|
|
|
24975
25107
|
}
|
|
24976
25108
|
});
|
|
24977
25109
|
|
|
25110
|
+
// src/rerank/http-provider.ts
|
|
25111
|
+
function buildRerankUrl(baseUrl) {
|
|
25112
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
25113
|
+
if (trimmed.endsWith("/rerank")) return trimmed;
|
|
25114
|
+
return `${trimmed}/rerank`;
|
|
25115
|
+
}
|
|
25116
|
+
function parseRerankResponse(payload) {
|
|
25117
|
+
const rows = extractRows(payload);
|
|
25118
|
+
if (rows.length === 0) {
|
|
25119
|
+
throw new Error("Neural rerank response contained no ranked results");
|
|
25120
|
+
}
|
|
25121
|
+
return rows.sort((a4, b4) => b4.score - a4.score);
|
|
25122
|
+
}
|
|
25123
|
+
function extractRows(payload) {
|
|
25124
|
+
if (Array.isArray(payload)) {
|
|
25125
|
+
return payload.map(rowFromUnknown).filter((row) => row !== null);
|
|
25126
|
+
}
|
|
25127
|
+
if (payload && typeof payload === "object" && "results" in payload) {
|
|
25128
|
+
const results = payload.results;
|
|
25129
|
+
if (Array.isArray(results)) {
|
|
25130
|
+
return results.map(rowFromUnknown).filter((row) => row !== null);
|
|
25131
|
+
}
|
|
25132
|
+
}
|
|
25133
|
+
throw new Error("Neural rerank response was not Cohere or TEI shaped");
|
|
25134
|
+
}
|
|
25135
|
+
function rowFromUnknown(value) {
|
|
25136
|
+
if (!value || typeof value !== "object") return null;
|
|
25137
|
+
const row = value;
|
|
25138
|
+
if (typeof row.index !== "number" || !Number.isFinite(row.index)) return null;
|
|
25139
|
+
const score = typeof row.relevance_score === "number" ? row.relevance_score : typeof row.score === "number" ? row.score : null;
|
|
25140
|
+
if (score === null || !Number.isFinite(score)) return null;
|
|
25141
|
+
return { index: row.index, score };
|
|
25142
|
+
}
|
|
25143
|
+
function buildRerankBody(query, documents, model) {
|
|
25144
|
+
const body = {
|
|
25145
|
+
query,
|
|
25146
|
+
documents,
|
|
25147
|
+
top_n: documents.length,
|
|
25148
|
+
return_documents: false
|
|
25149
|
+
};
|
|
25150
|
+
const trimmed = model?.trim();
|
|
25151
|
+
if (trimmed) body.model = trimmed;
|
|
25152
|
+
return body;
|
|
25153
|
+
}
|
|
25154
|
+
async function rerankViaHttp(query, documents, config2) {
|
|
25155
|
+
if (documents.length === 0) return [];
|
|
25156
|
+
const url2 = buildRerankUrl(config2.baseUrl);
|
|
25157
|
+
const headers = {
|
|
25158
|
+
"content-type": "application/json"
|
|
25159
|
+
};
|
|
25160
|
+
if (config2.apiKey) {
|
|
25161
|
+
headers.authorization = `Bearer ${config2.apiKey}`;
|
|
25162
|
+
}
|
|
25163
|
+
const controller = new AbortController();
|
|
25164
|
+
const timeoutMs = resolveRerankTimeoutMs(config2.timeoutMs);
|
|
25165
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
25166
|
+
try {
|
|
25167
|
+
const fetchImpl = config2.fetchImpl ?? fetch;
|
|
25168
|
+
const response = await fetchImpl(url2, {
|
|
25169
|
+
method: "POST",
|
|
25170
|
+
headers,
|
|
25171
|
+
signal: controller.signal,
|
|
25172
|
+
body: JSON.stringify(buildRerankBody(query, documents, config2.model))
|
|
25173
|
+
});
|
|
25174
|
+
if (!response.ok) {
|
|
25175
|
+
throw new Error(`Neural rerank HTTP ${response.status} from ${url2}`);
|
|
25176
|
+
}
|
|
25177
|
+
return parseRerankResponse(await response.json());
|
|
25178
|
+
} finally {
|
|
25179
|
+
clearTimeout(timer);
|
|
25180
|
+
}
|
|
25181
|
+
}
|
|
25182
|
+
var init_http_provider = __esm({
|
|
25183
|
+
"src/rerank/http-provider.ts"() {
|
|
25184
|
+
"use strict";
|
|
25185
|
+
init_esm_shims();
|
|
25186
|
+
init_policy();
|
|
25187
|
+
}
|
|
25188
|
+
});
|
|
25189
|
+
|
|
25190
|
+
// src/rerank/index.ts
|
|
25191
|
+
var rerank_exports = {};
|
|
25192
|
+
__export(rerank_exports, {
|
|
25193
|
+
DEFAULT_RERANK_TIMEOUT_MS: () => DEFAULT_RERANK_TIMEOUT_MS,
|
|
25194
|
+
MIN_RERANK_CANDIDATES: () => MIN_RERANK_CANDIDATES,
|
|
25195
|
+
isNeuralRerankEnabled: () => isNeuralRerankEnabled,
|
|
25196
|
+
neuralRerankCandidates: () => neuralRerankCandidates,
|
|
25197
|
+
parseRerankTimeoutMs: () => parseRerankTimeoutMs,
|
|
25198
|
+
resolveRerankTimeoutMs: () => resolveRerankTimeoutMs,
|
|
25199
|
+
shouldAttemptHttpRerank: () => shouldAttemptHttpRerank,
|
|
25200
|
+
shouldAttemptLlmRerank: () => shouldAttemptLlmRerank
|
|
25201
|
+
});
|
|
25202
|
+
function isNeuralRerankEnabled(options = {}) {
|
|
25203
|
+
const lane = getResolvedRerankLane(options);
|
|
25204
|
+
return lane.provider === "http" && Boolean(lane.baseUrl);
|
|
25205
|
+
}
|
|
25206
|
+
async function neuralRerankCandidates(query, candidates, options = {}) {
|
|
25207
|
+
if (!isNeuralRerankEnabled(options) || candidates.length === 0) return null;
|
|
25208
|
+
const lane = getResolvedRerankLane(options);
|
|
25209
|
+
if (!lane.canSendRequest || !lane.baseUrl) return null;
|
|
25210
|
+
const toRerank = candidates.slice(0, MAX_RERANK);
|
|
25211
|
+
const rest = candidates.slice(MAX_RERANK);
|
|
25212
|
+
const documents = toRerank.map((candidate2) => candidateText(candidate2));
|
|
25213
|
+
const ranked = await rerankViaHttp(query, documents, {
|
|
25214
|
+
provider: "http",
|
|
25215
|
+
model: lane.model,
|
|
25216
|
+
baseUrl: lane.baseUrl,
|
|
25217
|
+
apiKey: lane.apiKey,
|
|
25218
|
+
timeoutMs: resolveRerankTimeoutMs()
|
|
25219
|
+
});
|
|
25220
|
+
const seen = /* @__PURE__ */ new Set();
|
|
25221
|
+
const reranked = [];
|
|
25222
|
+
for (const row of ranked) {
|
|
25223
|
+
const candidate2 = toRerank[row.index];
|
|
25224
|
+
if (!candidate2 || seen.has(row.index)) continue;
|
|
25225
|
+
reranked.push(candidate2);
|
|
25226
|
+
seen.add(row.index);
|
|
25227
|
+
}
|
|
25228
|
+
for (const [index, candidate2] of toRerank.entries()) {
|
|
25229
|
+
if (!seen.has(index)) reranked.push(candidate2);
|
|
25230
|
+
}
|
|
25231
|
+
reranked.push(...rest);
|
|
25232
|
+
return reranked;
|
|
25233
|
+
}
|
|
25234
|
+
function candidateText(candidate2) {
|
|
25235
|
+
const narrative = candidate2.narrative?.trim();
|
|
25236
|
+
if (narrative) return `${candidate2.title} \u2014 ${narrative.slice(0, 200)}`;
|
|
25237
|
+
return candidate2.title;
|
|
25238
|
+
}
|
|
25239
|
+
var MAX_RERANK;
|
|
25240
|
+
var init_rerank = __esm({
|
|
25241
|
+
"src/rerank/index.ts"() {
|
|
25242
|
+
"use strict";
|
|
25243
|
+
init_esm_shims();
|
|
25244
|
+
init_resolved_config();
|
|
25245
|
+
init_http_provider();
|
|
25246
|
+
init_policy();
|
|
25247
|
+
init_policy();
|
|
25248
|
+
MAX_RERANK = 10;
|
|
25249
|
+
}
|
|
25250
|
+
});
|
|
25251
|
+
|
|
24978
25252
|
// src/llm/quality.ts
|
|
24979
25253
|
var quality_exports = {};
|
|
24980
25254
|
__export(quality_exports, {
|
|
@@ -25014,9 +25288,9 @@ async function rerankResults(query, candidates) {
|
|
|
25014
25288
|
if (!isLLMEnabled() || candidates.length <= 2) {
|
|
25015
25289
|
return { reranked: candidates, usedLLM: false };
|
|
25016
25290
|
}
|
|
25017
|
-
const
|
|
25018
|
-
const toRerank = candidates.slice(0,
|
|
25019
|
-
const rest = candidates.slice(
|
|
25291
|
+
const MAX_RERANK2 = 10;
|
|
25292
|
+
const toRerank = candidates.slice(0, MAX_RERANK2);
|
|
25293
|
+
const rest = candidates.slice(MAX_RERANK2);
|
|
25020
25294
|
try {
|
|
25021
25295
|
const candidateList = toRerank.map(
|
|
25022
25296
|
(c6) => `[ID: ${c6.id}] (${c6.type}) ${c6.title}${c6.narrative ? ` \u2014 ${c6.narrative.substring(0, 100)}` : ""}`
|
|
@@ -185792,46 +186066,78 @@ async function searchObservations(options) {
|
|
|
185792
186066
|
}
|
|
185793
186067
|
}
|
|
185794
186068
|
}
|
|
185795
|
-
const
|
|
185796
|
-
|
|
185797
|
-
|
|
185798
|
-
|
|
185799
|
-
})
|
|
185800
|
-
|
|
185801
|
-
|
|
185802
|
-
|
|
185803
|
-
|
|
185804
|
-
|
|
185805
|
-
|
|
185806
|
-
|
|
185807
|
-
|
|
185808
|
-
|
|
185809
|
-
|
|
185810
|
-
|
|
185811
|
-
|
|
185812
|
-
|
|
185813
|
-
|
|
185814
|
-
|
|
185815
|
-
|
|
185816
|
-
|
|
185817
|
-
|
|
185818
|
-
|
|
185819
|
-
|
|
185820
|
-
|
|
185821
|
-
|
|
185822
|
-
|
|
185823
|
-
|
|
185824
|
-
|
|
185825
|
-
|
|
185826
|
-
|
|
185827
|
-
|
|
185828
|
-
|
|
185829
|
-
|
|
185830
|
-
|
|
186069
|
+
const httpGate = shouldAttemptHttpRerank({
|
|
186070
|
+
quality,
|
|
186071
|
+
hasQuery: Boolean(hasQuery),
|
|
186072
|
+
candidateCount: intermediate.length
|
|
186073
|
+
});
|
|
186074
|
+
const llmGateWithoutHttp = shouldAttemptLlmRerank({
|
|
186075
|
+
quality,
|
|
186076
|
+
tier,
|
|
186077
|
+
hasQuery: Boolean(hasQuery),
|
|
186078
|
+
candidateCount: intermediate.length,
|
|
186079
|
+
topScore: intermediate[0]?.score ?? 0,
|
|
186080
|
+
secondScore: intermediate[1]?.score ?? 0,
|
|
186081
|
+
httpRerankConfigured: false
|
|
186082
|
+
});
|
|
186083
|
+
if (httpGate || llmGateWithoutHttp) {
|
|
186084
|
+
const narrativeMap = /* @__PURE__ */ new Map();
|
|
186085
|
+
for (const hit of results.hits) {
|
|
186086
|
+
const doc = hit.document;
|
|
186087
|
+
narrativeMap.set(makeEntryKey(doc.projectId, doc.observationId), doc.narrative);
|
|
186088
|
+
}
|
|
186089
|
+
const RERANK_TOP_K = 5;
|
|
186090
|
+
const toRerank = intermediate.slice(0, RERANK_TOP_K);
|
|
186091
|
+
const candidates = toRerank.map((e5, index) => ({
|
|
186092
|
+
id: `r${index + 1}`,
|
|
186093
|
+
title: e5.title,
|
|
186094
|
+
type: e5.type,
|
|
186095
|
+
score: e5.score,
|
|
186096
|
+
narrative: narrativeMap.get(makeEntryKey(e5.projectId, e5.id))
|
|
186097
|
+
}));
|
|
186098
|
+
const RERANK_TIMEOUT_MS = parseRerankTimeoutMs(process.env.MEMORIX_RERANK_TIMEOUT_MS);
|
|
186099
|
+
const candidateMap = new Map(candidates.map((candidate2, index) => [candidate2.id, toRerank[index]]));
|
|
186100
|
+
const { isNeuralRerankEnabled: isNeuralRerankEnabled2, neuralRerankCandidates: neuralRerankCandidates2 } = await Promise.resolve().then(() => (init_rerank(), rerank_exports));
|
|
186101
|
+
const httpConfigured = isNeuralRerankEnabled2();
|
|
186102
|
+
if (httpConfigured && httpGate) {
|
|
186103
|
+
try {
|
|
186104
|
+
const neural = await withTimeout(
|
|
186105
|
+
neuralRerankCandidates2(originalQuery, candidates),
|
|
186106
|
+
RERANK_TIMEOUT_MS,
|
|
186107
|
+
"neural rerank"
|
|
186108
|
+
);
|
|
186109
|
+
if (neural && neural.length > 0) {
|
|
186110
|
+
const rerankedTop = neural.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
186111
|
+
if (rerankedTop.length > 0) {
|
|
186112
|
+
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
186113
|
+
lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + neural rerank");
|
|
186114
|
+
mark("rerank(usedNeural=true)");
|
|
186115
|
+
}
|
|
185831
186116
|
}
|
|
186117
|
+
} catch {
|
|
186118
|
+
console.error("[memorix] neural rerank failed or timed out; keeping original order");
|
|
185832
186119
|
}
|
|
185833
|
-
}
|
|
185834
|
-
|
|
186120
|
+
} else if (!httpConfigured && llmGateWithoutHttp) {
|
|
186121
|
+
try {
|
|
186122
|
+
const { rerankResults: rerankResults2 } = await Promise.resolve().then(() => (init_quality(), quality_exports));
|
|
186123
|
+
const { reranked, usedLLM } = await withTimeout(
|
|
186124
|
+
rerankResults2(originalQuery, candidates),
|
|
186125
|
+
RERANK_TIMEOUT_MS,
|
|
186126
|
+
"LLM rerank"
|
|
186127
|
+
);
|
|
186128
|
+
mark(`rerank(usedLLM=${usedLLM})`);
|
|
186129
|
+
if (usedLLM) {
|
|
186130
|
+
lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + LLM rerank");
|
|
186131
|
+
const rerankedTop = reranked.map((row) => candidateMap.get(row.id)).filter((entry) => entry != null);
|
|
186132
|
+
if (rerankedTop.length > 0) {
|
|
186133
|
+
intermediate = [...rerankedTop, ...intermediate.slice(RERANK_TOP_K)];
|
|
186134
|
+
}
|
|
186135
|
+
}
|
|
186136
|
+
} catch {
|
|
186137
|
+
console.error("[memorix] LLM rerank failed or timed out, using original order");
|
|
186138
|
+
}
|
|
186139
|
+
} else {
|
|
186140
|
+
mark(`rerank(skipped,tier=${tier})`);
|
|
185835
186141
|
}
|
|
185836
186142
|
} else {
|
|
185837
186143
|
mark(`rerank(skipped,tier=${tier})`);
|
|
@@ -186013,6 +186319,7 @@ var init_orama_store = __esm({
|
|
|
186013
186319
|
init_project_affinity();
|
|
186014
186320
|
init_intent_detector();
|
|
186015
186321
|
init_query_expansion();
|
|
186322
|
+
init_policy();
|
|
186016
186323
|
init_timeout();
|
|
186017
186324
|
db = null;
|
|
186018
186325
|
dbInitPromise = null;
|
|
@@ -190318,6 +190625,16 @@ function buildInitTomlConfig(options) {
|
|
|
190318
190625
|
}
|
|
190319
190626
|
}
|
|
190320
190627
|
lines.push("");
|
|
190628
|
+
lines.push("[rerank]");
|
|
190629
|
+
lines.push("# Optional HTTP rerank against any Cohere-compatible /rerank API.");
|
|
190630
|
+
lines.push('# provider = "http"');
|
|
190631
|
+
lines.push('# model = "rerank-model"');
|
|
190632
|
+
lines.push("# base_url inherits [memory.llm] when unset.");
|
|
190633
|
+
if (isGlobal) {
|
|
190634
|
+
lines.push("# Bearer inherits the memory LLM key only when that endpoint matches.");
|
|
190635
|
+
lines.push("# A different rerank URL needs MEMORIX_RERANK_API_KEY.");
|
|
190636
|
+
}
|
|
190637
|
+
lines.push("");
|
|
190321
190638
|
lines.push("[git]");
|
|
190322
190639
|
lines.push(`auto_hook = ${options.gitAutoHook}`);
|
|
190323
190640
|
lines.push("ingest_on_commit = true");
|
|
@@ -190490,6 +190807,12 @@ var init_init = __esm({
|
|
|
190490
190807
|
envLines.push("# MEMORIX_EMBEDDING_BASE_URL=https://api.openai.com/v1");
|
|
190491
190808
|
envLines.push("");
|
|
190492
190809
|
}
|
|
190810
|
+
envLines.push("# Optional HTTP rerank (Cohere-compatible POST {base_url}/rerank)");
|
|
190811
|
+
envLines.push("# MEMORIX_RERANK_PROVIDER=http");
|
|
190812
|
+
envLines.push("# MEMORIX_RERANK_MODEL=rerank-model");
|
|
190813
|
+
envLines.push("# MEMORIX_RERANK_BASE_URL=https://api.example.com/v1");
|
|
190814
|
+
envLines.push("# MEMORIX_RERANK_API_KEY= # required when BASE_URL is not the memory LLM endpoint");
|
|
190815
|
+
envLines.push("");
|
|
190493
190816
|
envLines.push("# Optional memory LLM simple key (does not apply to embedding or agent lanes)");
|
|
190494
190817
|
envLines.push("# MEMORIX_API_KEY=sk-your-key-here");
|
|
190495
190818
|
envLines.push("");
|
|
@@ -194916,6 +195239,12 @@ function serializeResolvedConfigToToml(config2, options = {}) {
|
|
|
194916
195239
|
api_key: includeSecrets ? config2.embedding.apiKey : void 0,
|
|
194917
195240
|
dimensions: config2.embedding.dimensions
|
|
194918
195241
|
});
|
|
195242
|
+
writeSection(lines, "rerank", {
|
|
195243
|
+
provider: config2.rerank.provider,
|
|
195244
|
+
model: config2.rerank.model,
|
|
195245
|
+
base_url: config2.rerank.baseUrl,
|
|
195246
|
+
api_key: includeSecrets ? config2.rerank.apiKey : void 0
|
|
195247
|
+
});
|
|
194919
195248
|
writeSection(lines, "memory", {
|
|
194920
195249
|
inject: config2.memory.inject,
|
|
194921
195250
|
formation: config2.memory.formation,
|
|
@@ -259680,8 +260009,7 @@ async function callVisionLLM(systemPrompt, imageBase64, mimeType) {
|
|
|
259680
260009
|
if (!apiKey) {
|
|
259681
260010
|
throw new Error("No LLM API key configured for image analysis.");
|
|
259682
260011
|
}
|
|
259683
|
-
|
|
259684
|
-
if (!baseUrl.endsWith("/v1")) baseUrl += "/v1";
|
|
260012
|
+
const baseUrl = normalizeOpenAICompatibleBaseUrl(getLLMBaseUrl("https://api.openai.com/v1"));
|
|
259685
260013
|
const model = getLLMModel("gpt-4o");
|
|
259686
260014
|
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
259687
260015
|
method: "POST",
|
|
@@ -260220,7 +260548,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
260220
260548
|
};
|
|
260221
260549
|
const server = existingServer ?? new McpServer({
|
|
260222
260550
|
name: "memorix",
|
|
260223
|
-
version: true ? "1.7.
|
|
260551
|
+
version: true ? "1.7.3" : "1.0.1"
|
|
260224
260552
|
});
|
|
260225
260553
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
260226
260554
|
server.registerTool = ((name, ...args) => {
|
|
@@ -268586,6 +268914,7 @@ var init_status = __esm({
|
|
|
268586
268914
|
diagLines.push(` Agent lane: ${formatLane(agent.provider, agent.model, agent.baseUrl, agent.apiKey)}`);
|
|
268587
268915
|
diagLines.push(` Memory LLM lane: ${formatLane(resolved.memory.llm.provider, resolved.memory.llm.model, resolved.memory.llm.baseUrl, resolved.memory.llm.apiKey)}`);
|
|
268588
268916
|
diagLines.push(` Embedding lane: ${formatLane(resolved.embedding.provider, resolved.embedding.model, resolved.embedding.baseUrl, resolved.embedding.apiKey)}`);
|
|
268917
|
+
diagLines.push(` Rerank lane: ${formatLane(resolved.rerank.provider, resolved.rerank.model, resolved.rerank.baseUrl, resolved.rerank.apiKey)}`);
|
|
268589
268918
|
diagLines.push(` Memory behavior: inject=${resolved.memory.inject ?? "default"}, formation=${resolved.memory.formation ?? "default"}, autoCleanup=${resolved.memory.autoCleanup ?? "default"}`);
|
|
268590
268919
|
diagLines.push(` Git behavior: autoHook=${resolved.git.autoHook ?? "default"}, ingestOnCommit=${resolved.git.ingestOnCommit ?? "default"}, maxDiffSize=${resolved.git.maxDiffSize ?? "default"}, skipMergeCommits=${resolved.git.skipMergeCommits ?? "default"}`);
|
|
268591
268920
|
diagLines.push(` Server: transport=${resolved.server.transport ?? "default"}, dashboard=${resolved.server.dashboard ?? "default"}, dashboardPort=${resolved.server.dashboardPort ?? "default"}`);
|
|
@@ -268619,7 +268948,8 @@ var init_status = __esm({
|
|
|
268619
268948
|
lanes: {
|
|
268620
268949
|
agent: summarizeLane(agent.provider, agent.model, agent.baseUrl, agent.apiKey),
|
|
268621
268950
|
memoryLlm: summarizeLane(resolved.memory.llm.provider, resolved.memory.llm.model, resolved.memory.llm.baseUrl, resolved.memory.llm.apiKey),
|
|
268622
|
-
embedding: summarizeLane(resolved.embedding.provider, resolved.embedding.model, resolved.embedding.baseUrl, resolved.embedding.apiKey)
|
|
268951
|
+
embedding: summarizeLane(resolved.embedding.provider, resolved.embedding.model, resolved.embedding.baseUrl, resolved.embedding.apiKey),
|
|
268952
|
+
rerank: summarizeLane(resolved.rerank.provider, resolved.rerank.model, resolved.rerank.baseUrl, resolved.rerank.apiKey)
|
|
268623
268953
|
},
|
|
268624
268954
|
memory: {
|
|
268625
268955
|
inject: resolved.memory.inject ?? "default",
|
|
@@ -274942,7 +275272,9 @@ var init_doctor = __esm({
|
|
|
274942
275272
|
if (isLLMEnabled2()) {
|
|
274943
275273
|
const config2 = getLLMConfig2();
|
|
274944
275274
|
lines.push(ok(`Provider: ${config2?.provider}/${config2?.model}`));
|
|
274945
|
-
|
|
275275
|
+
const { isNeuralRerankEnabled: isNeuralRerankEnabled2 } = await Promise.resolve().then(() => (init_rerank(), rerank_exports));
|
|
275276
|
+
const rerankCap = isNeuralRerankEnabled2() ? "HTTP rerank" : "LLM rerank";
|
|
275277
|
+
lines.push(info2(`Capabilities: fact extraction, auto-dedup, ${rerankCap}`));
|
|
274946
275278
|
report.llm = { enabled: true, provider: config2?.provider, model: config2?.model };
|
|
274947
275279
|
} else {
|
|
274948
275280
|
lines.push(info2("LLM mode: off (heuristic dedup only)"));
|