memorix 1.5.0 → 1.5.1
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 +14 -0
- package/TEAM.md +86 -86
- package/dist/cli/index.js +211 -69
- package/dist/cli/memcode.js +0 -0
- package/dist/index.js +211 -69
- package/dist/maintenance-runner.js +169 -37
- package/dist/media-audio-runner.js +169 -37
- package/dist/media-video-runner.js +169 -37
- package/dist/memcode-runtime/CHANGELOG.md +14 -0
- package/dist/sdk.js +210 -68
- package/dist/types.d.ts +2 -0
- package/dist/vector-backfill-runner.js +169 -37
- package/docs/DESIGN_DECISIONS.md +357 -357
- 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/audit/index.ts +156 -156
- package/src/cli/commands/formation.ts +48 -48
- package/src/cli/commands/git-hook-install.ts +111 -111
- package/src/cli/commands/handoff.ts +54 -54
- package/src/cli/commands/hooks-status.ts +63 -63
- package/src/cli/commands/ingest.ts +44 -44
- package/src/cli/commands/integrate-shared.ts +15 -15
- package/src/cli/commands/lock.ts +82 -82
- package/src/cli/commands/message.ts +104 -104
- package/src/cli/commands/poll.ts +58 -58
- package/src/cli/commands/reasoning.ts +118 -118
- package/src/cli/commands/skills.ts +114 -114
- package/src/cli/commands/task.ts +167 -167
- package/src/cli/commands/transfer.ts +47 -47
- package/src/cli/index.ts +406 -406
- package/src/cli/tui/ChatView.tsx +234 -234
- package/src/cli/tui/CommandBar.tsx +312 -312
- package/src/cli/tui/ContextRail.tsx +118 -118
- package/src/cli/tui/HeaderBar.tsx +72 -72
- package/src/cli/tui/LogoBanner.tsx +51 -51
- package/src/cli/tui/index.ts +41 -41
- package/src/cli/version.ts +7 -7
- package/src/cli/workbench.ts +1 -1
- package/src/dashboard/project-classification.ts +64 -64
- package/src/embedding/api-provider.ts +105 -22
- package/src/embedding/provider.ts +2 -0
- package/src/git/hooks-path.ts +85 -85
- package/src/hooks/pattern-detector.ts +173 -173
- package/src/hooks/significance-filter.ts +250 -250
- package/src/llm/memory-manager.ts +328 -328
- package/src/llm/provider.ts +17 -8
- package/src/llm/quality.ts +248 -248
- package/src/memory/attribution-guard.ts +249 -249
- package/src/memory/disclosure-policy.ts +135 -135
- package/src/memory/entity-extractor.ts +197 -197
- package/src/memory/formation/evaluate.ts +217 -217
- package/src/memory/formation/extract.ts +6 -3
- package/src/memory/formation/index.ts +2 -1
- package/src/memory/formation/resolve.ts +10 -6
- package/src/memory/formation/types.ts +3 -1
- package/src/memory/freshness.ts +122 -122
- package/src/memory/graph.ts +197 -197
- package/src/memory/long-term.ts +7 -1
- package/src/memory/refs.ts +94 -94
- package/src/memory/secret-filter.ts +79 -79
- package/src/orchestrate/adapters/claude-stream.ts +192 -192
- package/src/orchestrate/adapters/claude.ts +111 -111
- package/src/orchestrate/adapters/codex-stream.ts +134 -134
- package/src/orchestrate/adapters/codex.ts +41 -41
- package/src/orchestrate/adapters/gemini-stream.ts +166 -166
- package/src/orchestrate/adapters/gemini.ts +42 -42
- package/src/orchestrate/adapters/index.ts +73 -73
- package/src/orchestrate/adapters/opencode-stream.ts +143 -143
- package/src/orchestrate/adapters/opencode.ts +47 -47
- package/src/orchestrate/adapters/types.ts +77 -77
- package/src/orchestrate/capability-router.ts +284 -284
- package/src/orchestrate/cost-tracker.ts +219 -219
- package/src/orchestrate/error-recovery.ts +191 -191
- package/src/orchestrate/evidence.ts +140 -140
- package/src/orchestrate/ledger.ts +110 -110
- package/src/orchestrate/memorix-bridge.ts +343 -343
- package/src/orchestrate/output-budget.ts +80 -80
- package/src/orchestrate/permission.ts +152 -152
- package/src/orchestrate/pipeline-trace.ts +131 -131
- package/src/orchestrate/prompt-builder.ts +155 -155
- package/src/orchestrate/ring-buffer.ts +37 -37
- package/src/orchestrate/task-graph.ts +389 -389
- package/src/project/aliases.ts +374 -374
- package/src/rules/adapters/trae.ts +56 -56
- package/src/rules/syncer.ts +235 -235
- package/src/search/query-expansion.ts +52 -52
- package/src/server/formation-timeout.ts +27 -27
- package/src/server.ts +14 -10
- package/src/skills/mini-skills.ts +386 -386
- package/src/store/chat-store.ts +119 -119
- package/src/store/graph-store.ts +249 -249
- package/src/store/mini-skill-store.ts +349 -349
- package/src/store/orama-store.ts +6 -4
- package/src/store/persistence-json.ts +212 -212
- package/src/store/persistence.ts +291 -291
- package/src/store/project-affinity.ts +195 -195
- package/src/team/event-bus.ts +76 -76
- package/src/team/handoff.ts +161 -161
- package/src/team/poll.ts +132 -132
- package/src/timeout.ts +67 -0
- package/src/types.ts +2 -0
- package/src/workspace/mcp-adapters/codex.ts +191 -191
- package/src/workspace/mcp-adapters/copilot.ts +105 -105
- package/src/workspace/mcp-adapters/cursor.ts +53 -53
- package/src/workspace/mcp-adapters/kiro.ts +64 -64
- package/src/workspace/mcp-adapters/opencode.ts +123 -123
- package/src/workspace/mcp-adapters/trae.ts +134 -134
- package/src/workspace/mcp-adapters/windsurf.ts +91 -91
- package/src/workspace/sanitizer.ts +60 -60
package/dist/index.js
CHANGED
|
@@ -3987,6 +3987,8 @@ function getPreferredBatchSize(config) {
|
|
|
3987
3987
|
}
|
|
3988
3988
|
function parseBatchLimit(error) {
|
|
3989
3989
|
if (!(error instanceof Error)) return null;
|
|
3990
|
+
const status = error instanceof EmbeddingAPIError ? error.status : Number(error.message.match(/Embedding API error \((\d{3})\)/i)?.[1] ?? 0);
|
|
3991
|
+
if (status > 0 && status !== 400) return null;
|
|
3990
3992
|
const explicit = error.message.match(/should not be larger than\s+(\d+)/i);
|
|
3991
3993
|
if (explicit) return parseInt(explicit[1], 10);
|
|
3992
3994
|
if (/batch size/i.test(error.message)) {
|
|
@@ -3999,37 +4001,99 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
|
|
|
3999
4001
|
const controller = new AbortController();
|
|
4000
4002
|
const timeoutMs = typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) ? Math.max(100, Math.min(Math.floor(options.timeoutMs), 6e4)) : 1e4;
|
|
4001
4003
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
4004
|
+
const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
|
|
4002
4005
|
let response;
|
|
4003
4006
|
try {
|
|
4004
4007
|
response = await fetch(url, {
|
|
4005
4008
|
method: "POST",
|
|
4006
4009
|
headers: nativeGemini ? { "Content-Type": "application/json", "x-goog-api-key": apiKey } : { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
|
|
4007
4010
|
body: JSON.stringify(body),
|
|
4008
|
-
signal
|
|
4011
|
+
signal
|
|
4009
4012
|
});
|
|
4010
4013
|
} catch (err) {
|
|
4011
4014
|
clearTimeout(timeout);
|
|
4012
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
4015
|
+
if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
|
|
4013
4016
|
throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url}`);
|
|
4014
4017
|
}
|
|
4015
4018
|
throw err;
|
|
4016
4019
|
}
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
+
try {
|
|
4021
|
+
if (response.ok) {
|
|
4022
|
+
return await raceWithAbort(
|
|
4023
|
+
response.json(),
|
|
4024
|
+
signal
|
|
4025
|
+
);
|
|
4026
|
+
}
|
|
4027
|
+
if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
|
|
4028
|
+
const delay2 = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
4029
|
+
const retryAfter = response.headers.get("retry-after");
|
|
4030
|
+
const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
|
|
4031
|
+
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay2;
|
|
4032
|
+
console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
|
|
4033
|
+
await waitForRetry(waitMs, options.signal);
|
|
4034
|
+
return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
|
|
4035
|
+
}
|
|
4036
|
+
const errorText2 = await raceWithAbort(
|
|
4037
|
+
response.text().catch(() => "unknown error"),
|
|
4038
|
+
signal
|
|
4039
|
+
);
|
|
4040
|
+
throw new EmbeddingAPIError(response.status, errorText2);
|
|
4041
|
+
} catch (err) {
|
|
4042
|
+
if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
|
|
4043
|
+
throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url}`);
|
|
4044
|
+
}
|
|
4045
|
+
throw err;
|
|
4046
|
+
} finally {
|
|
4047
|
+
clearTimeout(timeout);
|
|
4020
4048
|
}
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4049
|
+
}
|
|
4050
|
+
function abortError() {
|
|
4051
|
+
const error = new Error("Embedding API request aborted");
|
|
4052
|
+
error.name = "AbortError";
|
|
4053
|
+
return error;
|
|
4054
|
+
}
|
|
4055
|
+
function raceWithAbort(promise, signal) {
|
|
4056
|
+
if (signal.aborted) return Promise.reject(abortError());
|
|
4057
|
+
return new Promise((resolve2, reject) => {
|
|
4058
|
+
const onAbort = () => {
|
|
4059
|
+
signal.removeEventListener("abort", onAbort);
|
|
4060
|
+
reject(abortError());
|
|
4061
|
+
};
|
|
4062
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
4063
|
+
promise.then(
|
|
4064
|
+
(value) => {
|
|
4065
|
+
signal.removeEventListener("abort", onAbort);
|
|
4066
|
+
resolve2(value);
|
|
4067
|
+
},
|
|
4068
|
+
(error) => {
|
|
4069
|
+
signal.removeEventListener("abort", onAbort);
|
|
4070
|
+
reject(error);
|
|
4071
|
+
}
|
|
4072
|
+
);
|
|
4073
|
+
});
|
|
4074
|
+
}
|
|
4075
|
+
async function waitForRetry(waitMs, signal) {
|
|
4076
|
+
if (!signal) {
|
|
4026
4077
|
await new Promise((resolve2) => setTimeout(resolve2, waitMs));
|
|
4027
|
-
return
|
|
4078
|
+
return;
|
|
4028
4079
|
}
|
|
4029
|
-
const
|
|
4030
|
-
throw new Error(
|
|
4080
|
+
const abortSignal = signal;
|
|
4081
|
+
if (abortSignal.aborted) throw new Error("Embedding API retry aborted");
|
|
4082
|
+
await new Promise((resolve2, reject) => {
|
|
4083
|
+
const timer = setTimeout(done, waitMs);
|
|
4084
|
+
const onAbort = () => {
|
|
4085
|
+
clearTimeout(timer);
|
|
4086
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
4087
|
+
reject(new Error("Embedding API retry aborted"));
|
|
4088
|
+
};
|
|
4089
|
+
function done() {
|
|
4090
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
4091
|
+
resolve2();
|
|
4092
|
+
}
|
|
4093
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
4094
|
+
});
|
|
4031
4095
|
}
|
|
4032
|
-
var cache3, MAX_CACHE_SIZE3, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, APIEmbeddingProvider;
|
|
4096
|
+
var cache3, MAX_CACHE_SIZE3, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, EmbeddingAPIError, APIEmbeddingProvider;
|
|
4033
4097
|
var init_api_provider = __esm({
|
|
4034
4098
|
"src/embedding/api-provider.ts"() {
|
|
4035
4099
|
"use strict";
|
|
@@ -4048,6 +4112,14 @@ var init_api_provider = __esm({
|
|
|
4048
4112
|
DASHSCOPE_MAX_BATCH_SIZE = 10;
|
|
4049
4113
|
MAX_RETRIES2 = 3;
|
|
4050
4114
|
BASE_DELAY_MS = 500;
|
|
4115
|
+
EmbeddingAPIError = class extends Error {
|
|
4116
|
+
status;
|
|
4117
|
+
constructor(status, detail) {
|
|
4118
|
+
super(`Embedding API error (${status}): ${detail}`);
|
|
4119
|
+
this.name = "EmbeddingAPIError";
|
|
4120
|
+
this.status = status;
|
|
4121
|
+
}
|
|
4122
|
+
};
|
|
4051
4123
|
APIEmbeddingProvider = class _APIEmbeddingProvider {
|
|
4052
4124
|
name;
|
|
4053
4125
|
dimensions;
|
|
@@ -4259,15 +4331,14 @@ var init_api_provider = __esm({
|
|
|
4259
4331
|
}
|
|
4260
4332
|
} catch (error) {
|
|
4261
4333
|
const providerLimit = parseBatchLimit(error);
|
|
4262
|
-
|
|
4263
|
-
if (chunkTexts.length > 1 && fallbackSize < chunkTexts.length) {
|
|
4334
|
+
if (providerLimit !== null && chunkTexts.length > 1 && providerLimit < chunkTexts.length) {
|
|
4264
4335
|
console.error(
|
|
4265
|
-
`[memorix] Embedding batch too large for provider, retrying in chunks of ${
|
|
4336
|
+
`[memorix] Embedding batch too large for provider, retrying in chunks of ${providerLimit}`
|
|
4266
4337
|
);
|
|
4267
|
-
for (let start = 0; start < chunkTexts.length; start +=
|
|
4338
|
+
for (let start = 0; start < chunkTexts.length; start += providerLimit) {
|
|
4268
4339
|
await processChunk(
|
|
4269
|
-
chunkTexts.slice(start, start +
|
|
4270
|
-
chunkIndices.slice(start, start +
|
|
4340
|
+
chunkTexts.slice(start, start + providerLimit),
|
|
4341
|
+
chunkIndices.slice(start, start + providerLimit)
|
|
4271
4342
|
);
|
|
4272
4343
|
}
|
|
4273
4344
|
return;
|
|
@@ -5131,22 +5202,23 @@ function getLLMConfig() {
|
|
|
5131
5202
|
function setLLMConfig(config) {
|
|
5132
5203
|
currentConfig = config;
|
|
5133
5204
|
}
|
|
5134
|
-
async function callLLM(systemPrompt, userMessage) {
|
|
5205
|
+
async function callLLM(systemPrompt, userMessage, signal) {
|
|
5135
5206
|
if (!currentConfig) {
|
|
5136
5207
|
throw new Error("LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.");
|
|
5137
5208
|
}
|
|
5138
5209
|
if (currentConfig.provider === "anthropic") {
|
|
5139
|
-
return callAnthropic(systemPrompt, userMessage);
|
|
5210
|
+
return callAnthropic(systemPrompt, userMessage, signal);
|
|
5140
5211
|
}
|
|
5141
|
-
return callOpenAICompatible(systemPrompt, userMessage);
|
|
5212
|
+
return callOpenAICompatible(systemPrompt, userMessage, signal);
|
|
5142
5213
|
}
|
|
5143
|
-
async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
5214
|
+
async function callOpenAICompatible(systemPrompt, userMessage, signal) {
|
|
5144
5215
|
const config = currentConfig;
|
|
5145
5216
|
let base = config.baseUrl.replace(/\/+$/, "");
|
|
5146
5217
|
if (!base.endsWith("/v1")) base += "/v1";
|
|
5147
5218
|
const url = `${base}/chat/completions`;
|
|
5219
|
+
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
5148
5220
|
const response = await fetch(url, {
|
|
5149
|
-
signal:
|
|
5221
|
+
signal: fetchSignal,
|
|
5150
5222
|
method: "POST",
|
|
5151
5223
|
headers: {
|
|
5152
5224
|
"Content-Type": "application/json",
|
|
@@ -5163,10 +5235,10 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
|
5163
5235
|
})
|
|
5164
5236
|
});
|
|
5165
5237
|
if (!response.ok) {
|
|
5166
|
-
const error = await readResponseText(response,
|
|
5238
|
+
const error = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
|
|
5167
5239
|
throw new Error(`LLM API error (${response.status}): ${error}`);
|
|
5168
5240
|
}
|
|
5169
|
-
const data = await readResponseJson(response);
|
|
5241
|
+
const data = await readResponseJson(response, signal);
|
|
5170
5242
|
return {
|
|
5171
5243
|
content: data.choices[0]?.message?.content ?? "",
|
|
5172
5244
|
usage: data.usage ? {
|
|
@@ -5175,11 +5247,12 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
|
5175
5247
|
} : void 0
|
|
5176
5248
|
};
|
|
5177
5249
|
}
|
|
5178
|
-
async function callAnthropic(systemPrompt, userMessage) {
|
|
5250
|
+
async function callAnthropic(systemPrompt, userMessage, signal) {
|
|
5179
5251
|
const config = currentConfig;
|
|
5180
5252
|
const url = `${config.baseUrl}/messages`;
|
|
5253
|
+
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
5181
5254
|
const response = await fetch(url, {
|
|
5182
|
-
signal:
|
|
5255
|
+
signal: fetchSignal,
|
|
5183
5256
|
method: "POST",
|
|
5184
5257
|
headers: {
|
|
5185
5258
|
"Content-Type": "application/json",
|
|
@@ -5197,10 +5270,10 @@ async function callAnthropic(systemPrompt, userMessage) {
|
|
|
5197
5270
|
})
|
|
5198
5271
|
});
|
|
5199
5272
|
if (!response.ok) {
|
|
5200
|
-
const error = await readResponseText(response,
|
|
5273
|
+
const error = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
|
|
5201
5274
|
throw new Error(`Anthropic API error (${response.status}): ${error}`);
|
|
5202
5275
|
}
|
|
5203
|
-
const data = await readResponseJson(response);
|
|
5276
|
+
const data = await readResponseJson(response, signal);
|
|
5204
5277
|
return {
|
|
5205
5278
|
content: data.content[0]?.text ?? "",
|
|
5206
5279
|
usage: data.usage ? {
|
|
@@ -5705,6 +5778,57 @@ function withTimeout(promise, ms, label) {
|
|
|
5705
5778
|
);
|
|
5706
5779
|
});
|
|
5707
5780
|
}
|
|
5781
|
+
function withTimeoutSignal(operation, ms, label, parentSignal) {
|
|
5782
|
+
const controller = new AbortController();
|
|
5783
|
+
const signal = parentSignal ? AbortSignal.any([parentSignal, controller.signal]) : controller.signal;
|
|
5784
|
+
return new Promise((resolve2, reject) => {
|
|
5785
|
+
let settled = false;
|
|
5786
|
+
let timedOut = false;
|
|
5787
|
+
let timer;
|
|
5788
|
+
const cleanup = () => {
|
|
5789
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
5790
|
+
parentSignal?.removeEventListener("abort", onParentAbort);
|
|
5791
|
+
};
|
|
5792
|
+
const onParentAbort = () => {
|
|
5793
|
+
if (settled || timedOut) return;
|
|
5794
|
+
settled = true;
|
|
5795
|
+
cleanup();
|
|
5796
|
+
reject(parentSignal?.reason ?? new Error(`${label} aborted`));
|
|
5797
|
+
};
|
|
5798
|
+
parentSignal?.addEventListener("abort", onParentAbort, { once: true });
|
|
5799
|
+
timer = setTimeout(() => {
|
|
5800
|
+
if (settled) return;
|
|
5801
|
+
timedOut = true;
|
|
5802
|
+
controller.abort(new Error(`${label} timed out after ${ms}ms`));
|
|
5803
|
+
settled = true;
|
|
5804
|
+
cleanup();
|
|
5805
|
+
reject(new Error(`${label} timed out after ${ms}ms`));
|
|
5806
|
+
}, ms);
|
|
5807
|
+
let pending;
|
|
5808
|
+
try {
|
|
5809
|
+
pending = operation(signal);
|
|
5810
|
+
} catch (error) {
|
|
5811
|
+
settled = true;
|
|
5812
|
+
cleanup();
|
|
5813
|
+
reject(error);
|
|
5814
|
+
return;
|
|
5815
|
+
}
|
|
5816
|
+
pending.then(
|
|
5817
|
+
(value) => {
|
|
5818
|
+
if (settled) return;
|
|
5819
|
+
settled = true;
|
|
5820
|
+
cleanup();
|
|
5821
|
+
resolve2(value);
|
|
5822
|
+
},
|
|
5823
|
+
(error) => {
|
|
5824
|
+
if (settled) return;
|
|
5825
|
+
settled = true;
|
|
5826
|
+
cleanup();
|
|
5827
|
+
reject(timedOut ? new Error(`${label} timed out after ${ms}ms`) : error);
|
|
5828
|
+
}
|
|
5829
|
+
);
|
|
5830
|
+
});
|
|
5831
|
+
}
|
|
5708
5832
|
var init_timeout = __esm({
|
|
5709
5833
|
"src/timeout.ts"() {
|
|
5710
5834
|
"use strict";
|
|
@@ -6569,16 +6693,18 @@ async function searchObservations(options) {
|
|
|
6569
6693
|
);
|
|
6570
6694
|
} else {
|
|
6571
6695
|
const EMBEDDING_TIMEOUT_MS = 15e3;
|
|
6572
|
-
queryVector = await
|
|
6573
|
-
provider2.embedInput ? provider2.embedInput(
|
|
6696
|
+
queryVector = await withTimeoutSignal(
|
|
6697
|
+
(signal) => provider2.embedInput ? provider2.embedInput(
|
|
6574
6698
|
{ modality: "text", text: expandedEmbeddingQuery },
|
|
6575
|
-
{ intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false }
|
|
6699
|
+
{ intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false, signal }
|
|
6576
6700
|
) : provider2.embed(expandedEmbeddingQuery, {
|
|
6577
6701
|
timeoutMs: EMBEDDING_TIMEOUT_MS,
|
|
6578
|
-
retry: false
|
|
6702
|
+
retry: false,
|
|
6703
|
+
signal
|
|
6579
6704
|
}),
|
|
6580
6705
|
EMBEDDING_TIMEOUT_MS,
|
|
6581
|
-
"Embedding"
|
|
6706
|
+
"Embedding",
|
|
6707
|
+
options.signal
|
|
6582
6708
|
);
|
|
6583
6709
|
mark("embedding");
|
|
6584
6710
|
const cjkRatio = (originalQuery.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length / originalQuery.length;
|
|
@@ -144998,7 +145124,13 @@ async function maintainLongTermMemories(input) {
|
|
|
144998
145124
|
}
|
|
144999
145125
|
for (const group of groups.values()) {
|
|
145000
145126
|
if (group.length < 2) continue;
|
|
145001
|
-
group.sort((a, b) =>
|
|
145127
|
+
group.sort((a, b) => {
|
|
145128
|
+
const byCreatedAt = Date.parse(b.createdAt) - Date.parse(a.createdAt);
|
|
145129
|
+
if (byCreatedAt !== 0) return byCreatedAt;
|
|
145130
|
+
const byUpdatedAt = Date.parse(b.updatedAt) - Date.parse(a.updatedAt);
|
|
145131
|
+
if (byUpdatedAt !== 0) return byUpdatedAt;
|
|
145132
|
+
return b.id.localeCompare(a.id);
|
|
145133
|
+
});
|
|
145002
145134
|
const newest = group[0];
|
|
145003
145135
|
for (const older of group.slice(1)) {
|
|
145004
145136
|
try {
|
|
@@ -155333,13 +155465,13 @@ function verifyType(declaredType, narrative, title) {
|
|
|
155333
155465
|
}
|
|
155334
155466
|
return { type: declaredType, corrected: false };
|
|
155335
155467
|
}
|
|
155336
|
-
async function extractFactsWithLLM(narrative, title, existingFacts) {
|
|
155468
|
+
async function extractFactsWithLLM(narrative, title, existingFacts, signal) {
|
|
155337
155469
|
try {
|
|
155338
155470
|
const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
155339
155471
|
const input = `Title: ${title}
|
|
155340
155472
|
Content: ${narrative}${existingFacts.length > 0 ? `
|
|
155341
155473
|
Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
|
|
155342
|
-
const response = await callLLM2(LLM_EXTRACT_PROMPT, input);
|
|
155474
|
+
const response = await callLLM2(LLM_EXTRACT_PROMPT, input, signal);
|
|
155343
155475
|
const text2 = response.content.trim();
|
|
155344
155476
|
const jsonMatch = text2.match(/\{[\s\S]*\}/);
|
|
155345
155477
|
if (!jsonMatch) return [];
|
|
@@ -155348,15 +155480,16 @@ Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
|
|
|
155348
155480
|
if (!Array.isArray(facts)) return [];
|
|
155349
155481
|
const existingLower = new Set(existingFacts.map((f3) => f3.toLowerCase().trim()));
|
|
155350
155482
|
return facts.filter((f3) => typeof f3 === "string" && f3.length >= 5).filter((f3) => !existingLower.has(f3.toLowerCase().trim())).slice(0, 10);
|
|
155351
|
-
} catch {
|
|
155483
|
+
} catch (error) {
|
|
155484
|
+
if (signal?.aborted) throw error;
|
|
155352
155485
|
return [];
|
|
155353
155486
|
}
|
|
155354
155487
|
}
|
|
155355
|
-
async function runExtract(input, existingEntities, useLLM = false) {
|
|
155488
|
+
async function runExtract(input, existingEntities, useLLM = false, signal) {
|
|
155356
155489
|
const callerFacts = input.facts ?? [];
|
|
155357
155490
|
let extractedFacts;
|
|
155358
155491
|
if (useLLM) {
|
|
155359
|
-
extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts);
|
|
155492
|
+
extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts, signal);
|
|
155360
155493
|
if (extractedFacts.length === 0) {
|
|
155361
155494
|
extractedFacts = extractFacts2(input.narrative, callerFacts);
|
|
155362
155495
|
}
|
|
@@ -155576,7 +155709,7 @@ function mergeFacts2(oldFacts, newFacts) {
|
|
|
155576
155709
|
}
|
|
155577
155710
|
return merged;
|
|
155578
155711
|
}
|
|
155579
|
-
async function resolveWithLLM(extracted, hits, getObservation2) {
|
|
155712
|
+
async function resolveWithLLM(extracted, hits, getObservation2, signal) {
|
|
155580
155713
|
try {
|
|
155581
155714
|
const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
155582
155715
|
const existingMemories = hits.slice(0, 5).map((h2, i2) => ({
|
|
@@ -155593,7 +155726,7 @@ Facts: ${extracted.facts.join("; ")}
|
|
|
155593
155726
|
|
|
155594
155727
|
EXISTING MEMORIES:
|
|
155595
155728
|
${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Facts: ${m2.facts}`).join("\n")}`;
|
|
155596
|
-
const response = await callLLM2(LLM_RESOLVE_PROMPT, input);
|
|
155729
|
+
const response = await callLLM2(LLM_RESOLVE_PROMPT, input, signal);
|
|
155597
155730
|
const text2 = response.content.trim();
|
|
155598
155731
|
const jsonMatch = text2.match(/\{[\s\S]*\}/);
|
|
155599
155732
|
if (!jsonMatch) return null;
|
|
@@ -155630,7 +155763,8 @@ ${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Fact
|
|
|
155630
155763
|
};
|
|
155631
155764
|
}
|
|
155632
155765
|
return null;
|
|
155633
|
-
} catch {
|
|
155766
|
+
} catch (error) {
|
|
155767
|
+
if (signal?.aborted) throw error;
|
|
155634
155768
|
return null;
|
|
155635
155769
|
}
|
|
155636
155770
|
}
|
|
@@ -155648,19 +155782,20 @@ function scoreCandidate(extracted, candidate) {
|
|
|
155648
155782
|
const contradiction = hasContradiction(candidate.narrative, extracted.narrative);
|
|
155649
155783
|
return { score, searchSimilarity, entityMatch, richer, contradiction };
|
|
155650
155784
|
}
|
|
155651
|
-
async function runResolve(extracted, projectId, searchMemories, getObservation2, useLLM = false) {
|
|
155785
|
+
async function runResolve(extracted, projectId, searchMemories, getObservation2, useLLM = false, signal) {
|
|
155652
155786
|
const query = `${extracted.title} ${extracted.narrative.substring(0, 200)}`;
|
|
155653
155787
|
let hits;
|
|
155654
155788
|
try {
|
|
155655
|
-
hits = await searchMemories(query, 5, projectId);
|
|
155656
|
-
} catch {
|
|
155789
|
+
hits = await searchMemories(query, 5, projectId, signal);
|
|
155790
|
+
} catch (error) {
|
|
155791
|
+
if (signal?.aborted) throw error;
|
|
155657
155792
|
return { action: "new", reason: "Search unavailable, defaulting to new" };
|
|
155658
155793
|
}
|
|
155659
155794
|
if (hits.length === 0) {
|
|
155660
155795
|
return { action: "new", reason: "No similar existing memories found" };
|
|
155661
155796
|
}
|
|
155662
155797
|
if (useLLM) {
|
|
155663
|
-
const llmResult = await resolveWithLLM(extracted, hits, getObservation2);
|
|
155798
|
+
const llmResult = await resolveWithLLM(extracted, hits, getObservation2, signal);
|
|
155664
155799
|
if (llmResult) return llmResult;
|
|
155665
155800
|
}
|
|
155666
155801
|
const scored = hits.map((hit) => ({
|
|
@@ -156082,7 +156217,7 @@ async function runFormation(input, config) {
|
|
|
156082
156217
|
const existingEntities = config.getEntityNames();
|
|
156083
156218
|
const extractStartTime = Date.now();
|
|
156084
156219
|
emitStageEvent("extract", "start");
|
|
156085
|
-
const extraction = await runExtract(input, existingEntities, config.useLLM);
|
|
156220
|
+
const extraction = await runExtract(input, existingEntities, config.useLLM, config.signal);
|
|
156086
156221
|
stageDurationsMs.extract = Date.now() - extractStartTime;
|
|
156087
156222
|
emitStageEvent("extract", "success", stageDurationsMs.extract);
|
|
156088
156223
|
stagesCompleted = 1;
|
|
@@ -156102,7 +156237,8 @@ async function runFormation(input, config) {
|
|
|
156102
156237
|
input.projectId,
|
|
156103
156238
|
config.searchMemories,
|
|
156104
156239
|
config.getObservation,
|
|
156105
|
-
config.useLLM
|
|
156240
|
+
config.useLLM,
|
|
156241
|
+
config.signal
|
|
156106
156242
|
);
|
|
156107
156243
|
stageDurationsMs.resolve = Date.now() - resolveStartTime;
|
|
156108
156244
|
emitStageEvent("resolve", "success", stageDurationsMs.resolve);
|
|
@@ -165834,7 +165970,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
165834
165970
|
};
|
|
165835
165971
|
const server = existingServer ?? new McpServer({
|
|
165836
165972
|
name: "memorix",
|
|
165837
|
-
version: true ? "1.5.
|
|
165973
|
+
version: true ? "1.5.1" : "1.0.1"
|
|
165838
165974
|
});
|
|
165839
165975
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
165840
165976
|
server.registerTool = ((name, ...args) => {
|
|
@@ -166023,8 +166159,8 @@ The path should point to a directory containing a .git folder.`
|
|
|
166023
166159
|
mode: "active",
|
|
166024
166160
|
useLLM: isLLMEnabled(),
|
|
166025
166161
|
minValueScore: 0.3,
|
|
166026
|
-
searchMemories: async (q, limit2, pid) => {
|
|
166027
|
-
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader });
|
|
166162
|
+
searchMemories: async (q, limit2, pid, signal) => {
|
|
166163
|
+
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader, signal });
|
|
166028
166164
|
if (result.entries.length === 0) return [];
|
|
166029
166165
|
const details = await compactDetail(result.entries.map((e2) => e2.id), { reader });
|
|
166030
166166
|
return details.documents.map((d, i2) => ({
|
|
@@ -166054,16 +166190,19 @@ The path should point to a directory containing a .git folder.`
|
|
|
166054
166190
|
getEntityNames: () => graphManager.getEntityNames(),
|
|
166055
166191
|
onStageEvent: onFormationStageEvent
|
|
166056
166192
|
};
|
|
166057
|
-
formationResult = await
|
|
166058
|
-
|
|
166059
|
-
|
|
166060
|
-
|
|
166061
|
-
|
|
166062
|
-
|
|
166063
|
-
|
|
166064
|
-
|
|
166065
|
-
|
|
166066
|
-
|
|
166193
|
+
formationResult = await withTimeoutSignal(
|
|
166194
|
+
async (signal) => {
|
|
166195
|
+
formationConfig.signal = signal;
|
|
166196
|
+
return runFormation({
|
|
166197
|
+
entityName,
|
|
166198
|
+
type,
|
|
166199
|
+
title,
|
|
166200
|
+
narrative,
|
|
166201
|
+
facts: safeFacts,
|
|
166202
|
+
projectId: project.id,
|
|
166203
|
+
source: "explicit"
|
|
166204
|
+
}, formationConfig);
|
|
166205
|
+
},
|
|
166067
166206
|
FORMATION_TIMEOUT_MS,
|
|
166068
166207
|
"Formation pipeline"
|
|
166069
166208
|
);
|
|
@@ -166413,8 +166552,8 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
166413
166552
|
mode: formationMode,
|
|
166414
166553
|
useLLM: isLLMEnabled(),
|
|
166415
166554
|
minValueScore: 0.3,
|
|
166416
|
-
searchMemories: async (q, limit2, pid) => {
|
|
166417
|
-
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader });
|
|
166555
|
+
searchMemories: async (q, limit2, pid, signal) => {
|
|
166556
|
+
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader, signal });
|
|
166418
166557
|
if (result.entries.length === 0) return [];
|
|
166419
166558
|
const details = await compactDetail(result.entries.map((e2) => e2.id), { reader });
|
|
166420
166559
|
return details.documents.map((d, i2) => ({
|
|
@@ -166435,8 +166574,11 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
166435
166574
|
},
|
|
166436
166575
|
getEntityNames: () => graphManager.getEntityNames()
|
|
166437
166576
|
};
|
|
166438
|
-
const formed = await
|
|
166439
|
-
|
|
166577
|
+
const formed = await withTimeoutSignal(
|
|
166578
|
+
async (signal) => {
|
|
166579
|
+
formationConfig.signal = signal;
|
|
166580
|
+
return runFormation({ entityName, type, title, narrative, facts: safeFacts, projectId: project.id, source: "explicit", topicKey }, formationConfig);
|
|
166581
|
+
},
|
|
166440
166582
|
FORMATION_TIMEOUT_MS,
|
|
166441
166583
|
"Shadow formation"
|
|
166442
166584
|
);
|
|
@@ -170213,7 +170355,7 @@ var init_serve_shared = __esm({
|
|
|
170213
170355
|
|
|
170214
170356
|
// src/cli/version.ts
|
|
170215
170357
|
function getCliVersion() {
|
|
170216
|
-
return true ? "1.5.
|
|
170358
|
+
return true ? "1.5.1" : pkg.version;
|
|
170217
170359
|
}
|
|
170218
170360
|
var init_version3 = __esm({
|
|
170219
170361
|
"src/cli/version.ts"() {
|