memorix 1.4.6 → 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 +38 -0
- package/TEAM.md +86 -86
- package/dist/cli/index.js +225 -70
- package/dist/cli/memcode.js +0 -0
- package/dist/index.js +225 -70
- package/dist/maintenance-runner.js +183 -38
- package/dist/media-audio-runner.js +183 -38
- package/dist/media-video-runner.js +183 -38
- package/dist/memcode-runtime/CHANGELOG.md +38 -0
- package/dist/sdk.js +224 -69
- package/dist/types.d.ts +2 -0
- package/dist/vector-backfill-runner.js +183 -38
- package/docs/CONFIGURATION.md +12 -0
- 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/config.ts +23 -2
- 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
|
@@ -3373,6 +3373,7 @@ var init_resolved_config = __esm({
|
|
|
3373
3373
|
// src/config.ts
|
|
3374
3374
|
var config_exports = {};
|
|
3375
3375
|
__export(config_exports, {
|
|
3376
|
+
defaultEmbeddingModelFor: () => defaultEmbeddingModelFor,
|
|
3376
3377
|
getAgentLLMApiKey: () => getAgentLLMApiKey,
|
|
3377
3378
|
getAgentLLMBaseUrl: () => getAgentLLMBaseUrl,
|
|
3378
3379
|
getAgentLLMModel: () => getAgentLLMModel,
|
|
@@ -3435,7 +3436,19 @@ function getEmbeddingBaseUrl() {
|
|
|
3435
3436
|
return getResolvedEmbeddingLane().baseUrl || "https://api.openai.com/v1";
|
|
3436
3437
|
}
|
|
3437
3438
|
function getEmbeddingModel() {
|
|
3438
|
-
|
|
3439
|
+
const lane = getResolvedEmbeddingLane();
|
|
3440
|
+
return defaultEmbeddingModelFor(lane.baseUrl, lane.model);
|
|
3441
|
+
}
|
|
3442
|
+
function defaultEmbeddingModelFor(baseUrl, explicitModel) {
|
|
3443
|
+
if (explicitModel) return explicitModel;
|
|
3444
|
+
try {
|
|
3445
|
+
const url = baseUrl ? new URL(baseUrl) : null;
|
|
3446
|
+
if (url && (url.hostname === "openrouter.ai" || url.hostname.endsWith(".openrouter.ai"))) {
|
|
3447
|
+
return "qwen/qwen3-embedding-8b";
|
|
3448
|
+
}
|
|
3449
|
+
} catch {
|
|
3450
|
+
}
|
|
3451
|
+
return "text-embedding-3-small";
|
|
3439
3452
|
}
|
|
3440
3453
|
function getEmbeddingDimensions() {
|
|
3441
3454
|
return getResolvedEmbeddingLane().dimensions ?? null;
|
|
@@ -3974,6 +3987,8 @@ function getPreferredBatchSize(config) {
|
|
|
3974
3987
|
}
|
|
3975
3988
|
function parseBatchLimit(error) {
|
|
3976
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;
|
|
3977
3992
|
const explicit = error.message.match(/should not be larger than\s+(\d+)/i);
|
|
3978
3993
|
if (explicit) return parseInt(explicit[1], 10);
|
|
3979
3994
|
if (/batch size/i.test(error.message)) {
|
|
@@ -3986,37 +4001,99 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
|
|
|
3986
4001
|
const controller = new AbortController();
|
|
3987
4002
|
const timeoutMs = typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) ? Math.max(100, Math.min(Math.floor(options.timeoutMs), 6e4)) : 1e4;
|
|
3988
4003
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
4004
|
+
const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
|
|
3989
4005
|
let response;
|
|
3990
4006
|
try {
|
|
3991
4007
|
response = await fetch(url, {
|
|
3992
4008
|
method: "POST",
|
|
3993
4009
|
headers: nativeGemini ? { "Content-Type": "application/json", "x-goog-api-key": apiKey } : { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
|
|
3994
4010
|
body: JSON.stringify(body),
|
|
3995
|
-
signal
|
|
4011
|
+
signal
|
|
3996
4012
|
});
|
|
3997
4013
|
} catch (err) {
|
|
3998
4014
|
clearTimeout(timeout);
|
|
3999
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
4015
|
+
if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
|
|
4000
4016
|
throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url}`);
|
|
4001
4017
|
}
|
|
4002
4018
|
throw err;
|
|
4003
4019
|
}
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
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);
|
|
4007
4048
|
}
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4012
|
-
|
|
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) {
|
|
4013
4077
|
await new Promise((resolve2) => setTimeout(resolve2, waitMs));
|
|
4014
|
-
return
|
|
4078
|
+
return;
|
|
4015
4079
|
}
|
|
4016
|
-
const
|
|
4017
|
-
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
|
+
});
|
|
4018
4095
|
}
|
|
4019
|
-
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;
|
|
4020
4097
|
var init_api_provider = __esm({
|
|
4021
4098
|
"src/embedding/api-provider.ts"() {
|
|
4022
4099
|
"use strict";
|
|
@@ -4035,6 +4112,14 @@ var init_api_provider = __esm({
|
|
|
4035
4112
|
DASHSCOPE_MAX_BATCH_SIZE = 10;
|
|
4036
4113
|
MAX_RETRIES2 = 3;
|
|
4037
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
|
+
};
|
|
4038
4123
|
APIEmbeddingProvider = class _APIEmbeddingProvider {
|
|
4039
4124
|
name;
|
|
4040
4125
|
dimensions;
|
|
@@ -4246,15 +4331,14 @@ var init_api_provider = __esm({
|
|
|
4246
4331
|
}
|
|
4247
4332
|
} catch (error) {
|
|
4248
4333
|
const providerLimit = parseBatchLimit(error);
|
|
4249
|
-
|
|
4250
|
-
if (chunkTexts.length > 1 && fallbackSize < chunkTexts.length) {
|
|
4334
|
+
if (providerLimit !== null && chunkTexts.length > 1 && providerLimit < chunkTexts.length) {
|
|
4251
4335
|
console.error(
|
|
4252
|
-
`[memorix] Embedding batch too large for provider, retrying in chunks of ${
|
|
4336
|
+
`[memorix] Embedding batch too large for provider, retrying in chunks of ${providerLimit}`
|
|
4253
4337
|
);
|
|
4254
|
-
for (let start = 0; start < chunkTexts.length; start +=
|
|
4338
|
+
for (let start = 0; start < chunkTexts.length; start += providerLimit) {
|
|
4255
4339
|
await processChunk(
|
|
4256
|
-
chunkTexts.slice(start, start +
|
|
4257
|
-
chunkIndices.slice(start, start +
|
|
4340
|
+
chunkTexts.slice(start, start + providerLimit),
|
|
4341
|
+
chunkIndices.slice(start, start + providerLimit)
|
|
4258
4342
|
);
|
|
4259
4343
|
}
|
|
4260
4344
|
return;
|
|
@@ -5118,22 +5202,23 @@ function getLLMConfig() {
|
|
|
5118
5202
|
function setLLMConfig(config) {
|
|
5119
5203
|
currentConfig = config;
|
|
5120
5204
|
}
|
|
5121
|
-
async function callLLM(systemPrompt, userMessage) {
|
|
5205
|
+
async function callLLM(systemPrompt, userMessage, signal) {
|
|
5122
5206
|
if (!currentConfig) {
|
|
5123
5207
|
throw new Error("LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.");
|
|
5124
5208
|
}
|
|
5125
5209
|
if (currentConfig.provider === "anthropic") {
|
|
5126
|
-
return callAnthropic(systemPrompt, userMessage);
|
|
5210
|
+
return callAnthropic(systemPrompt, userMessage, signal);
|
|
5127
5211
|
}
|
|
5128
|
-
return callOpenAICompatible(systemPrompt, userMessage);
|
|
5212
|
+
return callOpenAICompatible(systemPrompt, userMessage, signal);
|
|
5129
5213
|
}
|
|
5130
|
-
async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
5214
|
+
async function callOpenAICompatible(systemPrompt, userMessage, signal) {
|
|
5131
5215
|
const config = currentConfig;
|
|
5132
5216
|
let base = config.baseUrl.replace(/\/+$/, "");
|
|
5133
5217
|
if (!base.endsWith("/v1")) base += "/v1";
|
|
5134
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);
|
|
5135
5220
|
const response = await fetch(url, {
|
|
5136
|
-
signal:
|
|
5221
|
+
signal: fetchSignal,
|
|
5137
5222
|
method: "POST",
|
|
5138
5223
|
headers: {
|
|
5139
5224
|
"Content-Type": "application/json",
|
|
@@ -5150,10 +5235,10 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
|
5150
5235
|
})
|
|
5151
5236
|
});
|
|
5152
5237
|
if (!response.ok) {
|
|
5153
|
-
const error = await readResponseText(response,
|
|
5238
|
+
const error = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
|
|
5154
5239
|
throw new Error(`LLM API error (${response.status}): ${error}`);
|
|
5155
5240
|
}
|
|
5156
|
-
const data = await readResponseJson(response);
|
|
5241
|
+
const data = await readResponseJson(response, signal);
|
|
5157
5242
|
return {
|
|
5158
5243
|
content: data.choices[0]?.message?.content ?? "",
|
|
5159
5244
|
usage: data.usage ? {
|
|
@@ -5162,11 +5247,12 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
|
5162
5247
|
} : void 0
|
|
5163
5248
|
};
|
|
5164
5249
|
}
|
|
5165
|
-
async function callAnthropic(systemPrompt, userMessage) {
|
|
5250
|
+
async function callAnthropic(systemPrompt, userMessage, signal) {
|
|
5166
5251
|
const config = currentConfig;
|
|
5167
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);
|
|
5168
5254
|
const response = await fetch(url, {
|
|
5169
|
-
signal:
|
|
5255
|
+
signal: fetchSignal,
|
|
5170
5256
|
method: "POST",
|
|
5171
5257
|
headers: {
|
|
5172
5258
|
"Content-Type": "application/json",
|
|
@@ -5184,10 +5270,10 @@ async function callAnthropic(systemPrompt, userMessage) {
|
|
|
5184
5270
|
})
|
|
5185
5271
|
});
|
|
5186
5272
|
if (!response.ok) {
|
|
5187
|
-
const error = await readResponseText(response,
|
|
5273
|
+
const error = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
|
|
5188
5274
|
throw new Error(`Anthropic API error (${response.status}): ${error}`);
|
|
5189
5275
|
}
|
|
5190
|
-
const data = await readResponseJson(response);
|
|
5276
|
+
const data = await readResponseJson(response, signal);
|
|
5191
5277
|
return {
|
|
5192
5278
|
content: data.content[0]?.text ?? "",
|
|
5193
5279
|
usage: data.usage ? {
|
|
@@ -5692,6 +5778,57 @@ function withTimeout(promise, ms, label) {
|
|
|
5692
5778
|
);
|
|
5693
5779
|
});
|
|
5694
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
|
+
}
|
|
5695
5832
|
var init_timeout = __esm({
|
|
5696
5833
|
"src/timeout.ts"() {
|
|
5697
5834
|
"use strict";
|
|
@@ -6556,16 +6693,18 @@ async function searchObservations(options) {
|
|
|
6556
6693
|
);
|
|
6557
6694
|
} else {
|
|
6558
6695
|
const EMBEDDING_TIMEOUT_MS = 15e3;
|
|
6559
|
-
queryVector = await
|
|
6560
|
-
provider2.embedInput ? provider2.embedInput(
|
|
6696
|
+
queryVector = await withTimeoutSignal(
|
|
6697
|
+
(signal) => provider2.embedInput ? provider2.embedInput(
|
|
6561
6698
|
{ modality: "text", text: expandedEmbeddingQuery },
|
|
6562
|
-
{ intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false }
|
|
6699
|
+
{ intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false, signal }
|
|
6563
6700
|
) : provider2.embed(expandedEmbeddingQuery, {
|
|
6564
6701
|
timeoutMs: EMBEDDING_TIMEOUT_MS,
|
|
6565
|
-
retry: false
|
|
6702
|
+
retry: false,
|
|
6703
|
+
signal
|
|
6566
6704
|
}),
|
|
6567
6705
|
EMBEDDING_TIMEOUT_MS,
|
|
6568
|
-
"Embedding"
|
|
6706
|
+
"Embedding",
|
|
6707
|
+
options.signal
|
|
6569
6708
|
);
|
|
6570
6709
|
mark("embedding");
|
|
6571
6710
|
const cjkRatio = (originalQuery.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length / originalQuery.length;
|
|
@@ -144985,7 +145124,13 @@ async function maintainLongTermMemories(input) {
|
|
|
144985
145124
|
}
|
|
144986
145125
|
for (const group of groups.values()) {
|
|
144987
145126
|
if (group.length < 2) continue;
|
|
144988
|
-
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
|
+
});
|
|
144989
145134
|
const newest = group[0];
|
|
144990
145135
|
for (const older of group.slice(1)) {
|
|
144991
145136
|
try {
|
|
@@ -155320,13 +155465,13 @@ function verifyType(declaredType, narrative, title) {
|
|
|
155320
155465
|
}
|
|
155321
155466
|
return { type: declaredType, corrected: false };
|
|
155322
155467
|
}
|
|
155323
|
-
async function extractFactsWithLLM(narrative, title, existingFacts) {
|
|
155468
|
+
async function extractFactsWithLLM(narrative, title, existingFacts, signal) {
|
|
155324
155469
|
try {
|
|
155325
155470
|
const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
155326
155471
|
const input = `Title: ${title}
|
|
155327
155472
|
Content: ${narrative}${existingFacts.length > 0 ? `
|
|
155328
155473
|
Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
|
|
155329
|
-
const response = await callLLM2(LLM_EXTRACT_PROMPT, input);
|
|
155474
|
+
const response = await callLLM2(LLM_EXTRACT_PROMPT, input, signal);
|
|
155330
155475
|
const text2 = response.content.trim();
|
|
155331
155476
|
const jsonMatch = text2.match(/\{[\s\S]*\}/);
|
|
155332
155477
|
if (!jsonMatch) return [];
|
|
@@ -155335,15 +155480,16 @@ Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
|
|
|
155335
155480
|
if (!Array.isArray(facts)) return [];
|
|
155336
155481
|
const existingLower = new Set(existingFacts.map((f3) => f3.toLowerCase().trim()));
|
|
155337
155482
|
return facts.filter((f3) => typeof f3 === "string" && f3.length >= 5).filter((f3) => !existingLower.has(f3.toLowerCase().trim())).slice(0, 10);
|
|
155338
|
-
} catch {
|
|
155483
|
+
} catch (error) {
|
|
155484
|
+
if (signal?.aborted) throw error;
|
|
155339
155485
|
return [];
|
|
155340
155486
|
}
|
|
155341
155487
|
}
|
|
155342
|
-
async function runExtract(input, existingEntities, useLLM = false) {
|
|
155488
|
+
async function runExtract(input, existingEntities, useLLM = false, signal) {
|
|
155343
155489
|
const callerFacts = input.facts ?? [];
|
|
155344
155490
|
let extractedFacts;
|
|
155345
155491
|
if (useLLM) {
|
|
155346
|
-
extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts);
|
|
155492
|
+
extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts, signal);
|
|
155347
155493
|
if (extractedFacts.length === 0) {
|
|
155348
155494
|
extractedFacts = extractFacts2(input.narrative, callerFacts);
|
|
155349
155495
|
}
|
|
@@ -155563,7 +155709,7 @@ function mergeFacts2(oldFacts, newFacts) {
|
|
|
155563
155709
|
}
|
|
155564
155710
|
return merged;
|
|
155565
155711
|
}
|
|
155566
|
-
async function resolveWithLLM(extracted, hits, getObservation2) {
|
|
155712
|
+
async function resolveWithLLM(extracted, hits, getObservation2, signal) {
|
|
155567
155713
|
try {
|
|
155568
155714
|
const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
155569
155715
|
const existingMemories = hits.slice(0, 5).map((h2, i2) => ({
|
|
@@ -155580,7 +155726,7 @@ Facts: ${extracted.facts.join("; ")}
|
|
|
155580
155726
|
|
|
155581
155727
|
EXISTING MEMORIES:
|
|
155582
155728
|
${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Facts: ${m2.facts}`).join("\n")}`;
|
|
155583
|
-
const response = await callLLM2(LLM_RESOLVE_PROMPT, input);
|
|
155729
|
+
const response = await callLLM2(LLM_RESOLVE_PROMPT, input, signal);
|
|
155584
155730
|
const text2 = response.content.trim();
|
|
155585
155731
|
const jsonMatch = text2.match(/\{[\s\S]*\}/);
|
|
155586
155732
|
if (!jsonMatch) return null;
|
|
@@ -155617,7 +155763,8 @@ ${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Fact
|
|
|
155617
155763
|
};
|
|
155618
155764
|
}
|
|
155619
155765
|
return null;
|
|
155620
|
-
} catch {
|
|
155766
|
+
} catch (error) {
|
|
155767
|
+
if (signal?.aborted) throw error;
|
|
155621
155768
|
return null;
|
|
155622
155769
|
}
|
|
155623
155770
|
}
|
|
@@ -155635,19 +155782,20 @@ function scoreCandidate(extracted, candidate) {
|
|
|
155635
155782
|
const contradiction = hasContradiction(candidate.narrative, extracted.narrative);
|
|
155636
155783
|
return { score, searchSimilarity, entityMatch, richer, contradiction };
|
|
155637
155784
|
}
|
|
155638
|
-
async function runResolve(extracted, projectId, searchMemories, getObservation2, useLLM = false) {
|
|
155785
|
+
async function runResolve(extracted, projectId, searchMemories, getObservation2, useLLM = false, signal) {
|
|
155639
155786
|
const query = `${extracted.title} ${extracted.narrative.substring(0, 200)}`;
|
|
155640
155787
|
let hits;
|
|
155641
155788
|
try {
|
|
155642
|
-
hits = await searchMemories(query, 5, projectId);
|
|
155643
|
-
} catch {
|
|
155789
|
+
hits = await searchMemories(query, 5, projectId, signal);
|
|
155790
|
+
} catch (error) {
|
|
155791
|
+
if (signal?.aborted) throw error;
|
|
155644
155792
|
return { action: "new", reason: "Search unavailable, defaulting to new" };
|
|
155645
155793
|
}
|
|
155646
155794
|
if (hits.length === 0) {
|
|
155647
155795
|
return { action: "new", reason: "No similar existing memories found" };
|
|
155648
155796
|
}
|
|
155649
155797
|
if (useLLM) {
|
|
155650
|
-
const llmResult = await resolveWithLLM(extracted, hits, getObservation2);
|
|
155798
|
+
const llmResult = await resolveWithLLM(extracted, hits, getObservation2, signal);
|
|
155651
155799
|
if (llmResult) return llmResult;
|
|
155652
155800
|
}
|
|
155653
155801
|
const scored = hits.map((hit) => ({
|
|
@@ -156069,7 +156217,7 @@ async function runFormation(input, config) {
|
|
|
156069
156217
|
const existingEntities = config.getEntityNames();
|
|
156070
156218
|
const extractStartTime = Date.now();
|
|
156071
156219
|
emitStageEvent("extract", "start");
|
|
156072
|
-
const extraction = await runExtract(input, existingEntities, config.useLLM);
|
|
156220
|
+
const extraction = await runExtract(input, existingEntities, config.useLLM, config.signal);
|
|
156073
156221
|
stageDurationsMs.extract = Date.now() - extractStartTime;
|
|
156074
156222
|
emitStageEvent("extract", "success", stageDurationsMs.extract);
|
|
156075
156223
|
stagesCompleted = 1;
|
|
@@ -156089,7 +156237,8 @@ async function runFormation(input, config) {
|
|
|
156089
156237
|
input.projectId,
|
|
156090
156238
|
config.searchMemories,
|
|
156091
156239
|
config.getObservation,
|
|
156092
|
-
config.useLLM
|
|
156240
|
+
config.useLLM,
|
|
156241
|
+
config.signal
|
|
156093
156242
|
);
|
|
156094
156243
|
stageDurationsMs.resolve = Date.now() - resolveStartTime;
|
|
156095
156244
|
emitStageEvent("resolve", "success", stageDurationsMs.resolve);
|
|
@@ -165821,7 +165970,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
165821
165970
|
};
|
|
165822
165971
|
const server = existingServer ?? new McpServer({
|
|
165823
165972
|
name: "memorix",
|
|
165824
|
-
version: true ? "1.
|
|
165973
|
+
version: true ? "1.5.1" : "1.0.1"
|
|
165825
165974
|
});
|
|
165826
165975
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
165827
165976
|
server.registerTool = ((name, ...args) => {
|
|
@@ -166010,8 +166159,8 @@ The path should point to a directory containing a .git folder.`
|
|
|
166010
166159
|
mode: "active",
|
|
166011
166160
|
useLLM: isLLMEnabled(),
|
|
166012
166161
|
minValueScore: 0.3,
|
|
166013
|
-
searchMemories: async (q, limit2, pid) => {
|
|
166014
|
-
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 });
|
|
166015
166164
|
if (result.entries.length === 0) return [];
|
|
166016
166165
|
const details = await compactDetail(result.entries.map((e2) => e2.id), { reader });
|
|
166017
166166
|
return details.documents.map((d, i2) => ({
|
|
@@ -166041,16 +166190,19 @@ The path should point to a directory containing a .git folder.`
|
|
|
166041
166190
|
getEntityNames: () => graphManager.getEntityNames(),
|
|
166042
166191
|
onStageEvent: onFormationStageEvent
|
|
166043
166192
|
};
|
|
166044
|
-
formationResult = await
|
|
166045
|
-
|
|
166046
|
-
|
|
166047
|
-
|
|
166048
|
-
|
|
166049
|
-
|
|
166050
|
-
|
|
166051
|
-
|
|
166052
|
-
|
|
166053
|
-
|
|
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
|
+
},
|
|
166054
166206
|
FORMATION_TIMEOUT_MS,
|
|
166055
166207
|
"Formation pipeline"
|
|
166056
166208
|
);
|
|
@@ -166400,8 +166552,8 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
166400
166552
|
mode: formationMode,
|
|
166401
166553
|
useLLM: isLLMEnabled(),
|
|
166402
166554
|
minValueScore: 0.3,
|
|
166403
|
-
searchMemories: async (q, limit2, pid) => {
|
|
166404
|
-
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 });
|
|
166405
166557
|
if (result.entries.length === 0) return [];
|
|
166406
166558
|
const details = await compactDetail(result.entries.map((e2) => e2.id), { reader });
|
|
166407
166559
|
return details.documents.map((d, i2) => ({
|
|
@@ -166422,8 +166574,11 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
166422
166574
|
},
|
|
166423
166575
|
getEntityNames: () => graphManager.getEntityNames()
|
|
166424
166576
|
};
|
|
166425
|
-
const formed = await
|
|
166426
|
-
|
|
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
|
+
},
|
|
166427
166582
|
FORMATION_TIMEOUT_MS,
|
|
166428
166583
|
"Shadow formation"
|
|
166429
166584
|
);
|
|
@@ -170200,7 +170355,7 @@ var init_serve_shared = __esm({
|
|
|
170200
170355
|
|
|
170201
170356
|
// src/cli/version.ts
|
|
170202
170357
|
function getCliVersion() {
|
|
170203
|
-
return true ? "1.
|
|
170358
|
+
return true ? "1.5.1" : pkg.version;
|
|
170204
170359
|
}
|
|
170205
170360
|
var init_version3 = __esm({
|
|
170206
170361
|
"src/cli/version.ts"() {
|