memorix 1.2.4 → 1.2.5
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 +13 -0
- package/dist/cli/index.js +147 -61
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +92 -55
- package/dist/index.js.map +1 -1
- package/dist/maintenance-runner.js +79 -35
- package/dist/maintenance-runner.js.map +1 -1
- package/dist/memcode-runtime/CHANGELOG.md +13 -0
- package/dist/sdk.d.ts +4 -2
- package/dist/sdk.js +93 -55
- package/dist/sdk.js.map +1 -1
- package/dist/types.d.ts +8 -1
- package/dist/types.js.map +1 -1
- package/docs/1.2.5-RETRIEVAL-PERFORMANCE.md +85 -0
- package/docs/PERFORMANCE.md +22 -1
- package/docs/dev-log/progress.txt +33 -8
- package/package.json +2 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/src/cli/commands/memory.ts +12 -3
- package/src/cli/commands/operator-shared.ts +74 -2
- package/src/cli/index.ts +2 -0
- package/src/config/resolved-config.ts +29 -4
- package/src/runtime/project-maintenance.ts +1 -14
- package/src/sdk.ts +4 -0
- package/src/server.ts +8 -18
- package/src/store/orama-store.ts +39 -18
- package/src/timeout.ts +23 -0
- package/src/types.ts +8 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.2.5] - 2026-07-27
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Explicit retrieval profiles** -- Search now accepts `fast`, `balanced` (default), or `thorough` through the CLI, MCP, and SDK. Fast is fully local, balanced keeps optional LLM work out of everyday retrieval, and thorough explicitly opts into configured LLM query refinement.
|
|
9
|
+
- **Reproducible retrieval evidence** -- Added `npm run benchmark:retrieval` for a clearly-labelled hot in-process SDK lexical benchmark with p50/p95/p99 output. It does not present CLI startup, MCP transport, remote embedding, or LLM latency as the same metric.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- **Lighter read-only CLI path** -- Memory search, detail, timeline, recent, graph context, and help no longer create session bookkeeping or maintenance-target metadata. Identity and visibility checks remain unchanged.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- **Completed searches no longer retain timeout watchdogs** -- Embedding, rerank, MCP search, and maintenance timeout paths share a helper that clears the timer when work settles. This removes the avoidable CLI exit delay caused by an already-completed optional rerank.
|
|
16
|
+
- **OpenRouter lane isolation** -- An embedding-only `OPENROUTER_API_KEY` no longer silently enables the memory LLM lane. It remains valid for a memory LLM only when that lane explicitly selects an OpenRouter provider or base URL.
|
|
17
|
+
|
|
5
18
|
## [1.2.4] - 2026-07-26
|
|
6
19
|
|
|
7
20
|
### Added
|
package/dist/cli/index.js
CHANGED
|
@@ -3212,7 +3212,7 @@ ${import_picocolors.default.gray(m3)} ${s2}
|
|
|
3212
3212
|
|
|
3213
3213
|
// src/cli/version.ts
|
|
3214
3214
|
function getCliVersion() {
|
|
3215
|
-
return true ? "1.2.
|
|
3215
|
+
return true ? "1.2.5" : pkg.version;
|
|
3216
3216
|
}
|
|
3217
3217
|
var init_version = __esm({
|
|
3218
3218
|
"src/cli/version.ts"() {
|
|
@@ -13763,6 +13763,25 @@ function getResolvedConfig(options2 = {}) {
|
|
|
13763
13763
|
const legacy = loadFileConfig();
|
|
13764
13764
|
const embeddingBaseUrl = first(process.env.MEMORIX_EMBEDDING_BASE_URL, toml.embedding?.base_url, yaml4.embedding?.baseUrl, legacy.embeddingApi?.baseUrl);
|
|
13765
13765
|
const openRouterEmbeddingApiKey = isOpenRouterUrl(embeddingBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
13766
|
+
const memoryLlmProvider = first(
|
|
13767
|
+
process.env.MEMORIX_LLM_PROVIDER,
|
|
13768
|
+
toml.memory?.llm?.provider,
|
|
13769
|
+
yaml4.llm?.provider,
|
|
13770
|
+
legacy.llm?.provider
|
|
13771
|
+
);
|
|
13772
|
+
const memoryLlmModel = first(
|
|
13773
|
+
process.env.MEMORIX_LLM_MODEL,
|
|
13774
|
+
toml.memory?.llm?.model,
|
|
13775
|
+
yaml4.llm?.model,
|
|
13776
|
+
legacy.llm?.model
|
|
13777
|
+
);
|
|
13778
|
+
const memoryLlmBaseUrl = first(
|
|
13779
|
+
process.env.MEMORIX_LLM_BASE_URL,
|
|
13780
|
+
toml.memory?.llm?.base_url,
|
|
13781
|
+
yaml4.llm?.baseUrl,
|
|
13782
|
+
legacy.llm?.baseUrl
|
|
13783
|
+
);
|
|
13784
|
+
const openRouterMemoryLlmApiKey = isOpenRouterMemoryLane(memoryLlmProvider, memoryLlmBaseUrl) ? process.env.OPENROUTER_API_KEY : void 0;
|
|
13766
13785
|
const resolved = {
|
|
13767
13786
|
agent: {
|
|
13768
13787
|
provider: first(
|
|
@@ -13800,9 +13819,9 @@ function getResolvedConfig(options2 = {}) {
|
|
|
13800
13819
|
autoCleanup: firstBool(toml.memory?.auto_cleanup, yaml4.behavior?.autoCleanup),
|
|
13801
13820
|
syncAdvisory: firstBool(toml.memory?.sync_advisory, yaml4.behavior?.syncAdvisory),
|
|
13802
13821
|
llm: {
|
|
13803
|
-
provider:
|
|
13804
|
-
model:
|
|
13805
|
-
baseUrl:
|
|
13822
|
+
provider: memoryLlmProvider,
|
|
13823
|
+
model: memoryLlmModel,
|
|
13824
|
+
baseUrl: memoryLlmBaseUrl,
|
|
13806
13825
|
apiKey: first(
|
|
13807
13826
|
process.env.MEMORIX_LLM_API_KEY,
|
|
13808
13827
|
process.env.MEMORIX_API_KEY,
|
|
@@ -13811,7 +13830,7 @@ function getResolvedConfig(options2 = {}) {
|
|
|
13811
13830
|
legacy.llm?.apiKey,
|
|
13812
13831
|
process.env.OPENAI_API_KEY,
|
|
13813
13832
|
process.env.ANTHROPIC_API_KEY,
|
|
13814
|
-
|
|
13833
|
+
openRouterMemoryLlmApiKey
|
|
13815
13834
|
)
|
|
13816
13835
|
}
|
|
13817
13836
|
},
|
|
@@ -13948,6 +13967,9 @@ function isOpenRouterUrl(value) {
|
|
|
13948
13967
|
return /(^|\.)openrouter\.ai(?::|\/|$)/i.test(value);
|
|
13949
13968
|
}
|
|
13950
13969
|
}
|
|
13970
|
+
function isOpenRouterMemoryLane(provider2, baseUrl) {
|
|
13971
|
+
return provider2?.trim().toLowerCase() === "openrouter" || isOpenRouterUrl(baseUrl);
|
|
13972
|
+
}
|
|
13951
13973
|
function normalizeExternalContext(value) {
|
|
13952
13974
|
const normalized = value?.trim().toLowerCase();
|
|
13953
13975
|
if (normalized === "auto" || normalized === "off") return normalized;
|
|
@@ -15995,6 +16017,29 @@ Rules:
|
|
|
15995
16017
|
}
|
|
15996
16018
|
});
|
|
15997
16019
|
|
|
16020
|
+
// src/timeout.ts
|
|
16021
|
+
function withTimeout(promise, ms, label) {
|
|
16022
|
+
return new Promise((resolve6, reject) => {
|
|
16023
|
+
const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
|
|
16024
|
+
promise.then(
|
|
16025
|
+
(value) => {
|
|
16026
|
+
clearTimeout(timer);
|
|
16027
|
+
resolve6(value);
|
|
16028
|
+
},
|
|
16029
|
+
(error2) => {
|
|
16030
|
+
clearTimeout(timer);
|
|
16031
|
+
reject(error2);
|
|
16032
|
+
}
|
|
16033
|
+
);
|
|
16034
|
+
});
|
|
16035
|
+
}
|
|
16036
|
+
var init_timeout = __esm({
|
|
16037
|
+
"src/timeout.ts"() {
|
|
16038
|
+
"use strict";
|
|
16039
|
+
init_esm_shims();
|
|
16040
|
+
}
|
|
16041
|
+
});
|
|
16042
|
+
|
|
15998
16043
|
// src/project/aliases.ts
|
|
15999
16044
|
var aliases_exports = {};
|
|
16000
16045
|
__export(aliases_exports, {
|
|
@@ -19599,8 +19644,12 @@ async function searchObservations(options2) {
|
|
|
19599
19644
|
}
|
|
19600
19645
|
};
|
|
19601
19646
|
const modeKey = options2.projectId ?? SEARCH_MODE_DEFAULT_KEY;
|
|
19602
|
-
|
|
19647
|
+
const quality = options2.quality ?? "balanced";
|
|
19603
19648
|
const database = await getDb();
|
|
19649
|
+
lastSearchModeByProject.set(
|
|
19650
|
+
modeKey,
|
|
19651
|
+
quality === "fast" ? "fulltext (fast profile)" : embeddingEnabled ? "hybrid" : "fulltext"
|
|
19652
|
+
);
|
|
19604
19653
|
let projectIds = null;
|
|
19605
19654
|
if (options2.projectId) {
|
|
19606
19655
|
try {
|
|
@@ -19622,11 +19671,15 @@ async function searchObservations(options2) {
|
|
|
19622
19671
|
}
|
|
19623
19672
|
const hasQuery = options2.query && options2.query.trim().length > 0;
|
|
19624
19673
|
const originalQuery = options2.query;
|
|
19625
|
-
const tier = hasQuery ? classifyQueryTier(originalQuery) : "fast";
|
|
19674
|
+
const tier = quality === "fast" ? "fast" : hasQuery ? classifyQueryTier(originalQuery) : "fast";
|
|
19626
19675
|
mark(`tier=${tier}`);
|
|
19627
|
-
|
|
19676
|
+
if (quality === "thorough" && hasQuery) {
|
|
19677
|
+
const { initLLM: initLLM2, isLLMEnabled: isLLMEnabled2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
19678
|
+
if (!isLLMEnabled2()) initLLM2();
|
|
19679
|
+
}
|
|
19680
|
+
const expandedEmbeddingQuery = quality === "thorough" && tier === "heavy" ? await maybeExpandSearchQuery(options2.query) : options2.query;
|
|
19628
19681
|
mark("queryExpansion");
|
|
19629
|
-
const intentResult = hasQuery ? detectQueryIntent(originalQuery)
|
|
19682
|
+
const intentResult = quality === "fast" || !hasQuery ? null : detectQueryIntent(originalQuery);
|
|
19630
19683
|
const requestLimit = projectIds ? (options2.limit ?? 20) * 3 : options2.limit ?? 20;
|
|
19631
19684
|
const defaultBoost = {
|
|
19632
19685
|
title: 3,
|
|
@@ -19640,17 +19693,21 @@ async function searchObservations(options2) {
|
|
|
19640
19693
|
let searchParams = {
|
|
19641
19694
|
term: originalQuery,
|
|
19642
19695
|
limit: requestLimit,
|
|
19643
|
-
|
|
19696
|
+
// Fast search never uses vectors, so returning them only adds work and
|
|
19697
|
+
// payload pressure to an explicitly latency-sensitive path.
|
|
19698
|
+
includeVectors: quality !== "fast",
|
|
19644
19699
|
...Object.keys(filters).length > 0 ? { where: filters } : {},
|
|
19645
19700
|
// Search specific fields (not tokens, accessCount, etc.)
|
|
19646
19701
|
properties: ["title", "entityName", "narrative", "facts", "concepts", "filesModified"],
|
|
19647
19702
|
// Field boosting: intent-aware or default
|
|
19648
19703
|
boost: fieldBoost,
|
|
19649
19704
|
// Fuzzy tolerance: allow 1-char typos for short queries, 2 for longer
|
|
19650
|
-
|
|
19705
|
+
// Fuzzy matching is useful for ordinary recall, but grows sharply with
|
|
19706
|
+
// corpus size. The fast profile deliberately uses exact lexical matching.
|
|
19707
|
+
...hasQuery && quality !== "fast" ? { tolerance: originalQuery.length > 6 ? 2 : 1 } : {}
|
|
19651
19708
|
};
|
|
19652
19709
|
let queryVector = null;
|
|
19653
|
-
if (embeddingEnabled && hasQuery && tier !== "fast") {
|
|
19710
|
+
if (quality !== "fast" && embeddingEnabled && hasQuery && tier !== "fast") {
|
|
19654
19711
|
try {
|
|
19655
19712
|
const provider2 = await getEmbeddingProvider();
|
|
19656
19713
|
if (provider2) {
|
|
@@ -19665,11 +19722,11 @@ async function searchObservations(options2) {
|
|
|
19665
19722
|
);
|
|
19666
19723
|
} else {
|
|
19667
19724
|
const EMBEDDING_TIMEOUT_MS = 15e3;
|
|
19668
|
-
|
|
19669
|
-
|
|
19670
|
-
|
|
19725
|
+
queryVector = await withTimeout(
|
|
19726
|
+
provider2.embed(expandedEmbeddingQuery),
|
|
19727
|
+
EMBEDDING_TIMEOUT_MS,
|
|
19728
|
+
"Embedding"
|
|
19671
19729
|
);
|
|
19672
|
-
queryVector = await Promise.race([embedPromise, timeoutPromise]);
|
|
19673
19730
|
mark("embedding");
|
|
19674
19731
|
const cjkRatio = (originalQuery.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length / originalQuery.length;
|
|
19675
19732
|
const isCJKHeavy = cjkRatio > 0.3;
|
|
@@ -19910,7 +19967,7 @@ async function searchObservations(options2) {
|
|
|
19910
19967
|
}
|
|
19911
19968
|
}
|
|
19912
19969
|
}
|
|
19913
|
-
const shouldRerank = tier === "heavy" && hasQuery && intermediate.length > 2 && (() => {
|
|
19970
|
+
const shouldRerank = quality === "thorough" && tier === "heavy" && hasQuery && intermediate.length > 2 && (() => {
|
|
19914
19971
|
const top = intermediate[0]?.score ?? 0;
|
|
19915
19972
|
const second2 = intermediate[1]?.score ?? 0;
|
|
19916
19973
|
return top > 0 && second2 / top > 0.7;
|
|
@@ -19934,11 +19991,11 @@ async function searchObservations(options2) {
|
|
|
19934
19991
|
}));
|
|
19935
19992
|
const _parsedRerank = parseInt(process.env.MEMORIX_RERANK_TIMEOUT_MS || "", 10);
|
|
19936
19993
|
const RERANK_TIMEOUT_MS = Number.isFinite(_parsedRerank) && _parsedRerank > 0 ? _parsedRerank : 5e3;
|
|
19937
|
-
const
|
|
19938
|
-
|
|
19939
|
-
|
|
19994
|
+
const { reranked, usedLLM } = await withTimeout(
|
|
19995
|
+
rerankResults2(originalQuery, candidates),
|
|
19996
|
+
RERANK_TIMEOUT_MS,
|
|
19997
|
+
"LLM rerank"
|
|
19940
19998
|
);
|
|
19941
|
-
const { reranked, usedLLM } = await Promise.race([rerankPromise, timeoutPromise]);
|
|
19942
19999
|
mark(`rerank(usedLLM=${usedLLM})`);
|
|
19943
20000
|
if (usedLLM) {
|
|
19944
20001
|
lastSearchModeByProject.set(modeKey, (lastSearchModeByProject.get(modeKey) ?? "fulltext") + " + LLM rerank");
|
|
@@ -20131,6 +20188,7 @@ var init_orama_store = __esm({
|
|
|
20131
20188
|
init_project_affinity();
|
|
20132
20189
|
init_intent_detector();
|
|
20133
20190
|
init_query_expansion();
|
|
20191
|
+
init_timeout();
|
|
20134
20192
|
db = null;
|
|
20135
20193
|
dbInitPromise = null;
|
|
20136
20194
|
dbGeneration = 0;
|
|
@@ -23491,7 +23549,7 @@ var init_session_store = __esm({
|
|
|
23491
23549
|
});
|
|
23492
23550
|
|
|
23493
23551
|
// src/cli/commands/operator-shared.ts
|
|
23494
|
-
async function
|
|
23552
|
+
async function resolveCliProjectContext(options2) {
|
|
23495
23553
|
const invocation = getCliInvocation();
|
|
23496
23554
|
const detection = detectProjectWithDiagnostics(
|
|
23497
23555
|
options2?.projectRoot ?? invocation.projectRoot ?? process.env.MEMORIX_PROJECT_ROOT ?? process.cwd()
|
|
@@ -23502,6 +23560,40 @@ async function getCliProjectContext(options2) {
|
|
|
23502
23560
|
}
|
|
23503
23561
|
const project = detection.project;
|
|
23504
23562
|
const dataDir = await getProjectDataDir(project.id);
|
|
23563
|
+
return { project, dataDir, invocation };
|
|
23564
|
+
}
|
|
23565
|
+
async function getCliReadContext(options2) {
|
|
23566
|
+
const { project, dataDir, invocation } = await resolveCliProjectContext(options2);
|
|
23567
|
+
await initObservations(dataDir);
|
|
23568
|
+
if (options2?.searchIndex) {
|
|
23569
|
+
await prepareSearchIndex();
|
|
23570
|
+
}
|
|
23571
|
+
const storedIdentity = await loadCliIdentity(dataDir, project.id);
|
|
23572
|
+
if (!invocation.actorId && !storedIdentity) {
|
|
23573
|
+
return {
|
|
23574
|
+
project,
|
|
23575
|
+
dataDir,
|
|
23576
|
+
reader: { projectId: project.id },
|
|
23577
|
+
identity: null
|
|
23578
|
+
};
|
|
23579
|
+
}
|
|
23580
|
+
const teamStore = await initTeamStore(dataDir);
|
|
23581
|
+
const identity = await resolveCliIdentity({
|
|
23582
|
+
project,
|
|
23583
|
+
dataDir,
|
|
23584
|
+
teamStore,
|
|
23585
|
+
explicitActorId: invocation.actorId
|
|
23586
|
+
});
|
|
23587
|
+
return {
|
|
23588
|
+
project,
|
|
23589
|
+
dataDir,
|
|
23590
|
+
reader: identity.reader,
|
|
23591
|
+
identity: identity.identity,
|
|
23592
|
+
...identity.warning ? { identityWarning: identity.warning } : {}
|
|
23593
|
+
};
|
|
23594
|
+
}
|
|
23595
|
+
async function getCliProjectContext(options2) {
|
|
23596
|
+
const { project, dataDir, invocation } = await resolveCliProjectContext(options2);
|
|
23505
23597
|
try {
|
|
23506
23598
|
const { MaintenanceTargetStore: MaintenanceTargetStore2 } = await Promise.resolve().then(() => (init_maintenance_targets(), maintenance_targets_exports));
|
|
23507
23599
|
new MaintenanceTargetStore2(dataDir).register({
|
|
@@ -23583,6 +23675,13 @@ function coerceObservationStatus(input) {
|
|
|
23583
23675
|
}
|
|
23584
23676
|
return normalized;
|
|
23585
23677
|
}
|
|
23678
|
+
function coerceRetrievalQuality(input) {
|
|
23679
|
+
const normalized = (input ?? "balanced").trim().toLowerCase();
|
|
23680
|
+
if (!RETRIEVAL_QUALITIES.includes(normalized)) {
|
|
23681
|
+
throw new Error("quality must be fast, balanced, or thorough");
|
|
23682
|
+
}
|
|
23683
|
+
return normalized;
|
|
23684
|
+
}
|
|
23586
23685
|
function coerceObservationVisibility(input) {
|
|
23587
23686
|
const normalized = (input ?? "project").trim().toLowerCase();
|
|
23588
23687
|
if (normalized === "personal" || normalized === "project" || normalized === "team") {
|
|
@@ -23613,7 +23712,7 @@ function resolveCliActorId(explicitValue, identity, field = "agentId") {
|
|
|
23613
23712
|
}
|
|
23614
23713
|
return explicit || identity?.agentId;
|
|
23615
23714
|
}
|
|
23616
|
-
var OBSERVATION_TYPES, OBSERVATION_STATUSES;
|
|
23715
|
+
var OBSERVATION_TYPES, OBSERVATION_STATUSES, RETRIEVAL_QUALITIES;
|
|
23617
23716
|
var init_operator_shared = __esm({
|
|
23618
23717
|
"src/cli/commands/operator-shared.ts"() {
|
|
23619
23718
|
"use strict";
|
|
@@ -23639,6 +23738,7 @@ var init_operator_shared = __esm({
|
|
|
23639
23738
|
"probe"
|
|
23640
23739
|
];
|
|
23641
23740
|
OBSERVATION_STATUSES = ["active", "resolved", "archived"];
|
|
23741
|
+
RETRIEVAL_QUALITIES = ["fast", "balanced", "thorough"];
|
|
23642
23742
|
}
|
|
23643
23743
|
});
|
|
23644
23744
|
|
|
@@ -24063,6 +24163,7 @@ var init_memory = __esm({
|
|
|
24063
24163
|
topicKey: { type: "string", description: "Stable topic key override" },
|
|
24064
24164
|
action: { type: "string", description: "Secondary action for advanced memory commands" },
|
|
24065
24165
|
limit: { type: "string", description: "Limit for search/recent output" },
|
|
24166
|
+
quality: { type: "string", description: "Retrieval profile: fast, balanced (default), or thorough" },
|
|
24066
24167
|
graphLimit: { type: "string", description: "Limit for graph-context output" },
|
|
24067
24168
|
graphQuery: { type: "string", description: "Query for graph-context packet" },
|
|
24068
24169
|
format: { type: "string", description: "Output format for graph-context: summary or prompt" },
|
|
@@ -24082,7 +24183,10 @@ var init_memory = __esm({
|
|
|
24082
24183
|
const positional = (args._ ?? []).slice(1);
|
|
24083
24184
|
const asJson = !!args.json;
|
|
24084
24185
|
try {
|
|
24085
|
-
const
|
|
24186
|
+
const readOnlyActions = /* @__PURE__ */ new Set(["", "search", "graph-context", "recent", "suggest-topic-key", "detail", "timeline"]);
|
|
24187
|
+
const needsSearchIndex = action === "search" || action === "detail" || action === "timeline";
|
|
24188
|
+
const context = readOnlyActions.has(action) ? await getCliReadContext({ searchIndex: needsSearchIndex }) : await getCliProjectContext({ searchIndex: true });
|
|
24189
|
+
const { project, dataDir, reader, identity } = context;
|
|
24086
24190
|
switch (action) {
|
|
24087
24191
|
case "search": {
|
|
24088
24192
|
const query = getStringArg(args.query, positional);
|
|
@@ -24091,7 +24195,8 @@ var init_memory = __esm({
|
|
|
24091
24195
|
return;
|
|
24092
24196
|
}
|
|
24093
24197
|
const limit = parsePositiveInt(args.limit, 10);
|
|
24094
|
-
const
|
|
24198
|
+
const quality = coerceRetrievalQuality(args.quality);
|
|
24199
|
+
const result = await compactSearch({ query, limit, quality, projectId: project.id, reader });
|
|
24095
24200
|
emitResult({ project, entries: result.entries }, result.formatted, asJson);
|
|
24096
24201
|
return;
|
|
24097
24202
|
}
|
|
@@ -24396,7 +24501,7 @@ var init_memory = __esm({
|
|
|
24396
24501
|
console.log("Memorix Memory Commands");
|
|
24397
24502
|
console.log("");
|
|
24398
24503
|
console.log("Usage:");
|
|
24399
|
-
console.log(' memorix memory search --query "timeout bug" [--limit 10]');
|
|
24504
|
+
console.log(' memorix memory search --query "timeout bug" [--limit 10] [--quality fast|balanced|thorough]');
|
|
24400
24505
|
console.log(" memorix memory recent [--limit 10]");
|
|
24401
24506
|
console.log(' memorix memory store --text "..." [--title "..."] [--type discovery] [--visibility project|personal|team]');
|
|
24402
24507
|
console.log(' memorix memory suggest-topic-key --type decision --title "..."');
|
|
@@ -67802,21 +67907,6 @@ async function loadWorkspaceForMaintenance(projectId, projectDir2, mode) {
|
|
|
67802
67907
|
]);
|
|
67803
67908
|
return versioned ?? local;
|
|
67804
67909
|
}
|
|
67805
|
-
function withTimeout(promise, ms, label) {
|
|
67806
|
-
return new Promise((resolve6, reject) => {
|
|
67807
|
-
const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
|
|
67808
|
-
promise.then(
|
|
67809
|
-
(value) => {
|
|
67810
|
-
clearTimeout(timer);
|
|
67811
|
-
resolve6(value);
|
|
67812
|
-
},
|
|
67813
|
-
(error2) => {
|
|
67814
|
-
clearTimeout(timer);
|
|
67815
|
-
reject(error2);
|
|
67816
|
-
}
|
|
67817
|
-
);
|
|
67818
|
-
});
|
|
67819
|
-
}
|
|
67820
67910
|
async function runAutomaticConsolidation(projectId, projectDir2, options2) {
|
|
67821
67911
|
const { isLLMEnabled: isLLMEnabled2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
67822
67912
|
if (!isLLMEnabled2()) {
|
|
@@ -68201,6 +68291,7 @@ var init_project_maintenance = __esm({
|
|
|
68201
68291
|
init_esm_shims();
|
|
68202
68292
|
init_isolated_maintenance();
|
|
68203
68293
|
init_lifecycle();
|
|
68294
|
+
init_timeout();
|
|
68204
68295
|
DEFAULT_VECTOR_BATCH_SIZE = 12;
|
|
68205
68296
|
DEFAULT_RETENTION_BATCH_SIZE = 100;
|
|
68206
68297
|
DEFAULT_CONSOLIDATION_BATCH_SIZE = 200;
|
|
@@ -69960,15 +70051,6 @@ __export(server_exports2, {
|
|
|
69960
70051
|
shouldAwaitProjectRuntime: () => shouldAwaitProjectRuntime
|
|
69961
70052
|
});
|
|
69962
70053
|
import { createHash as createHash14 } from "crypto";
|
|
69963
|
-
function withTimeout2(promise, ms, label) {
|
|
69964
|
-
let timer;
|
|
69965
|
-
return Promise.race([
|
|
69966
|
-
promise,
|
|
69967
|
-
new Promise((_4, reject) => {
|
|
69968
|
-
timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
|
|
69969
|
-
})
|
|
69970
|
-
]).finally(() => clearTimeout(timer));
|
|
69971
|
-
}
|
|
69972
70054
|
function formatFormationStageDurations(stageDurationsMs) {
|
|
69973
70055
|
const orderedStages = ["extract", "resolve", "evaluate"];
|
|
69974
70056
|
const parts = orderedStages.filter((stage) => stageDurationsMs[stage] !== void 0).map((stage) => `${stage}=${stageDurationsMs[stage]}ms`);
|
|
@@ -70323,7 +70405,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
70323
70405
|
};
|
|
70324
70406
|
const server = existingServer ?? new McpServer({
|
|
70325
70407
|
name: "memorix",
|
|
70326
|
-
version: true ? "1.2.
|
|
70408
|
+
version: true ? "1.2.5" : "1.0.1"
|
|
70327
70409
|
});
|
|
70328
70410
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
70329
70411
|
server.registerTool = ((name, ...args) => {
|
|
@@ -70520,7 +70602,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
70520
70602
|
getEntityNames: () => graphManager.getEntityNames(),
|
|
70521
70603
|
onStageEvent: onFormationStageEvent
|
|
70522
70604
|
};
|
|
70523
|
-
formationResult = await
|
|
70605
|
+
formationResult = await withTimeout(
|
|
70524
70606
|
runFormation({
|
|
70525
70607
|
entityName,
|
|
70526
70608
|
type,
|
|
@@ -70641,7 +70723,7 @@ ${modeIcon} Formation[active]: ${formationResult.evaluation.category} (${formati
|
|
|
70641
70723
|
facts: d3.facts,
|
|
70642
70724
|
score: similarEntries[i2]?.score ?? 0
|
|
70643
70725
|
}));
|
|
70644
|
-
const decision = await
|
|
70726
|
+
const decision = await withTimeout(
|
|
70645
70727
|
compactOnWrite(
|
|
70646
70728
|
{ title, narrative, facts: safeFacts ?? [] },
|
|
70647
70729
|
existingMemories
|
|
@@ -70737,7 +70819,7 @@ Mode: ${decision.usedLLM ? "LLM" : "heuristic"}`
|
|
|
70737
70819
|
let compressionNote = "";
|
|
70738
70820
|
try {
|
|
70739
70821
|
const { compressNarrative: compressNarrative2 } = await Promise.resolve().then(() => (init_quality(), quality_exports));
|
|
70740
|
-
const { compressed, saved, usedLLM } = await
|
|
70822
|
+
const { compressed, saved, usedLLM } = await withTimeout(
|
|
70741
70823
|
compressNarrative2(narrative, safeFacts, type),
|
|
70742
70824
|
COMPRESSION_TIMEOUT_MS,
|
|
70743
70825
|
"Narrative compression"
|
|
@@ -70859,7 +70941,7 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
70859
70941
|
},
|
|
70860
70942
|
getEntityNames: () => graphManager.getEntityNames()
|
|
70861
70943
|
};
|
|
70862
|
-
const formed = await
|
|
70944
|
+
const formed = await withTimeout(
|
|
70863
70945
|
runFormation({ entityName, type, title, narrative, facts: safeFacts, projectId: project.id, source: "explicit", topicKey }, formationConfig),
|
|
70864
70946
|
FORMATION_TIMEOUT_MS,
|
|
70865
70947
|
"Shadow formation"
|
|
@@ -70950,6 +71032,9 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
70950
71032
|
source: external_exports.enum(["agent", "git", "manual"]).optional().describe(
|
|
70951
71033
|
'Filter by memory source. "git" returns only commit-derived ground truth memories. Omit for all sources.'
|
|
70952
71034
|
),
|
|
71035
|
+
quality: external_exports.enum(["fast", "balanced", "thorough"]).optional().default("balanced").describe(
|
|
71036
|
+
"Retrieval profile: fast stays local, balanced uses configured embeddings, thorough explicitly permits optional LLM refinement."
|
|
71037
|
+
),
|
|
70953
71038
|
purpose: external_exports.string().optional().describe(
|
|
70954
71039
|
"Why this must expand beyond the latest Autopilot brief. Name the missing fact or the user's explicit request."
|
|
70955
71040
|
),
|
|
@@ -70958,7 +71043,7 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
70958
71043
|
)
|
|
70959
71044
|
}
|
|
70960
71045
|
},
|
|
70961
|
-
async ({ query, limit, type, maxTokens, scope, since, until, status, source, purpose, force }) => {
|
|
71046
|
+
async ({ query, limit, type, maxTokens, scope, since, until, status, source, quality, purpose, force }) => {
|
|
70962
71047
|
if (scope !== "global") {
|
|
70963
71048
|
const unresolved = requireResolvedProject("search the current project");
|
|
70964
71049
|
if (unresolved) return unresolved;
|
|
@@ -70983,16 +71068,14 @@ Use this as the \`topicKey\` parameter in \`memorix_store\` to enable upsert beh
|
|
|
70983
71068
|
projectId: scope === "global" ? void 0 : project.id,
|
|
70984
71069
|
status: status ?? "active",
|
|
70985
71070
|
source,
|
|
71071
|
+
quality,
|
|
70986
71072
|
reader: getObservationReader(scope === "global" ? "global" : "project")
|
|
70987
71073
|
});
|
|
70988
|
-
const timeoutPromise = new Promise(
|
|
70989
|
-
(_4, reject) => setTimeout(() => reject(new Error(`Search timeout after ${TIMEOUT_MS}ms`)), TIMEOUT_MS)
|
|
70990
|
-
);
|
|
70991
71074
|
let result;
|
|
70992
71075
|
try {
|
|
70993
|
-
result = await
|
|
71076
|
+
result = await withTimeout(searchPromise, TIMEOUT_MS, "Search");
|
|
70994
71077
|
} catch (error2) {
|
|
70995
|
-
if (error2 instanceof Error && error2.message
|
|
71078
|
+
if (error2 instanceof Error && /\btimeout\b|timed out/i.test(error2.message)) {
|
|
70996
71079
|
return {
|
|
70997
71080
|
content: [
|
|
70998
71081
|
{
|
|
@@ -74085,6 +74168,7 @@ var init_server4 = __esm({
|
|
|
74085
74168
|
init_memory_manager();
|
|
74086
74169
|
init_formation();
|
|
74087
74170
|
init_formation_timeout();
|
|
74171
|
+
init_timeout();
|
|
74088
74172
|
FORMATION_TIMEOUT_MS = parseFormationTimeoutMs(process.env.MEMORIX_FORMATION_TIMEOUT_MS);
|
|
74089
74173
|
COMPACT_ON_WRITE_TIMEOUT_MS = 12e3;
|
|
74090
74174
|
COMPRESSION_TIMEOUT_MS = 5e3;
|
|
@@ -91533,12 +91617,14 @@ var main = defineCommand({
|
|
|
91533
91617
|
args: {
|
|
91534
91618
|
query: { type: "positional", description: "Search query", required: true },
|
|
91535
91619
|
limit: { type: "string", description: "Maximum results" },
|
|
91620
|
+
quality: { type: "string", description: "Retrieval profile: fast, balanced (default), or thorough" },
|
|
91536
91621
|
json: { type: "boolean", description: "Emit machine-readable JSON output" }
|
|
91537
91622
|
},
|
|
91538
91623
|
async run({ args }) {
|
|
91539
91624
|
await runMemoryShortcut("search", {
|
|
91540
91625
|
query: args.query,
|
|
91541
91626
|
limit: args.limit,
|
|
91627
|
+
quality: args.quality,
|
|
91542
91628
|
json: args.json
|
|
91543
91629
|
});
|
|
91544
91630
|
}
|