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/cli/index.js
CHANGED
|
@@ -3221,7 +3221,7 @@ ${import_picocolors.default.gray(m3)} ${s4}
|
|
|
3221
3221
|
|
|
3222
3222
|
// src/cli/version.ts
|
|
3223
3223
|
function getCliVersion() {
|
|
3224
|
-
return true ? "1.
|
|
3224
|
+
return true ? "1.5.1" : pkg.version;
|
|
3225
3225
|
}
|
|
3226
3226
|
var init_version = __esm({
|
|
3227
3227
|
"src/cli/version.ts"() {
|
|
@@ -21713,6 +21713,7 @@ var init_resolved_config = __esm({
|
|
|
21713
21713
|
// src/config.ts
|
|
21714
21714
|
var config_exports = {};
|
|
21715
21715
|
__export(config_exports, {
|
|
21716
|
+
defaultEmbeddingModelFor: () => defaultEmbeddingModelFor,
|
|
21716
21717
|
getAgentLLMApiKey: () => getAgentLLMApiKey,
|
|
21717
21718
|
getAgentLLMBaseUrl: () => getAgentLLMBaseUrl,
|
|
21718
21719
|
getAgentLLMModel: () => getAgentLLMModel,
|
|
@@ -21775,7 +21776,19 @@ function getEmbeddingBaseUrl() {
|
|
|
21775
21776
|
return getResolvedEmbeddingLane().baseUrl || "https://api.openai.com/v1";
|
|
21776
21777
|
}
|
|
21777
21778
|
function getEmbeddingModel() {
|
|
21778
|
-
|
|
21779
|
+
const lane = getResolvedEmbeddingLane();
|
|
21780
|
+
return defaultEmbeddingModelFor(lane.baseUrl, lane.model);
|
|
21781
|
+
}
|
|
21782
|
+
function defaultEmbeddingModelFor(baseUrl, explicitModel) {
|
|
21783
|
+
if (explicitModel) return explicitModel;
|
|
21784
|
+
try {
|
|
21785
|
+
const url2 = baseUrl ? new URL(baseUrl) : null;
|
|
21786
|
+
if (url2 && (url2.hostname === "openrouter.ai" || url2.hostname.endsWith(".openrouter.ai"))) {
|
|
21787
|
+
return "qwen/qwen3-embedding-8b";
|
|
21788
|
+
}
|
|
21789
|
+
} catch {
|
|
21790
|
+
}
|
|
21791
|
+
return "text-embedding-3-small";
|
|
21779
21792
|
}
|
|
21780
21793
|
function getEmbeddingDimensions() {
|
|
21781
21794
|
return getResolvedEmbeddingLane().dimensions ?? null;
|
|
@@ -22314,6 +22327,8 @@ function getPreferredBatchSize(config2) {
|
|
|
22314
22327
|
}
|
|
22315
22328
|
function parseBatchLimit(error40) {
|
|
22316
22329
|
if (!(error40 instanceof Error)) return null;
|
|
22330
|
+
const status = error40 instanceof EmbeddingAPIError ? error40.status : Number(error40.message.match(/Embedding API error \((\d{3})\)/i)?.[1] ?? 0);
|
|
22331
|
+
if (status > 0 && status !== 400) return null;
|
|
22317
22332
|
const explicit = error40.message.match(/should not be larger than\s+(\d+)/i);
|
|
22318
22333
|
if (explicit) return parseInt(explicit[1], 10);
|
|
22319
22334
|
if (/batch size/i.test(error40.message)) {
|
|
@@ -22326,37 +22341,99 @@ async function fetchWithRetry(url2, apiKey, body, options = {}, attempt = 0, nat
|
|
|
22326
22341
|
const controller = new AbortController();
|
|
22327
22342
|
const timeoutMs = typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) ? Math.max(100, Math.min(Math.floor(options.timeoutMs), 6e4)) : 1e4;
|
|
22328
22343
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
22344
|
+
const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
|
|
22329
22345
|
let response;
|
|
22330
22346
|
try {
|
|
22331
22347
|
response = await fetch(url2, {
|
|
22332
22348
|
method: "POST",
|
|
22333
22349
|
headers: nativeGemini ? { "Content-Type": "application/json", "x-goog-api-key": apiKey } : { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
|
|
22334
22350
|
body: JSON.stringify(body),
|
|
22335
|
-
signal
|
|
22351
|
+
signal
|
|
22336
22352
|
});
|
|
22337
22353
|
} catch (err) {
|
|
22338
22354
|
clearTimeout(timeout);
|
|
22339
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
22355
|
+
if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
|
|
22340
22356
|
throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url2}`);
|
|
22341
22357
|
}
|
|
22342
22358
|
throw err;
|
|
22343
22359
|
}
|
|
22344
|
-
|
|
22345
|
-
|
|
22346
|
-
|
|
22360
|
+
try {
|
|
22361
|
+
if (response.ok) {
|
|
22362
|
+
return await raceWithAbort(
|
|
22363
|
+
response.json(),
|
|
22364
|
+
signal
|
|
22365
|
+
);
|
|
22366
|
+
}
|
|
22367
|
+
if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
|
|
22368
|
+
const delay2 = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
22369
|
+
const retryAfter = response.headers.get("retry-after");
|
|
22370
|
+
const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
|
|
22371
|
+
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay2;
|
|
22372
|
+
console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
|
|
22373
|
+
await waitForRetry(waitMs, options.signal);
|
|
22374
|
+
return fetchWithRetry(url2, apiKey, body, options, attempt + 1, nativeGemini);
|
|
22375
|
+
}
|
|
22376
|
+
const errorText2 = await raceWithAbort(
|
|
22377
|
+
response.text().catch(() => "unknown error"),
|
|
22378
|
+
signal
|
|
22379
|
+
);
|
|
22380
|
+
throw new EmbeddingAPIError(response.status, errorText2);
|
|
22381
|
+
} catch (err) {
|
|
22382
|
+
if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
|
|
22383
|
+
throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url2}`);
|
|
22384
|
+
}
|
|
22385
|
+
throw err;
|
|
22386
|
+
} finally {
|
|
22387
|
+
clearTimeout(timeout);
|
|
22347
22388
|
}
|
|
22348
|
-
|
|
22349
|
-
|
|
22350
|
-
|
|
22351
|
-
|
|
22352
|
-
|
|
22389
|
+
}
|
|
22390
|
+
function abortError() {
|
|
22391
|
+
const error40 = new Error("Embedding API request aborted");
|
|
22392
|
+
error40.name = "AbortError";
|
|
22393
|
+
return error40;
|
|
22394
|
+
}
|
|
22395
|
+
function raceWithAbort(promise2, signal) {
|
|
22396
|
+
if (signal.aborted) return Promise.reject(abortError());
|
|
22397
|
+
return new Promise((resolve6, reject) => {
|
|
22398
|
+
const onAbort = () => {
|
|
22399
|
+
signal.removeEventListener("abort", onAbort);
|
|
22400
|
+
reject(abortError());
|
|
22401
|
+
};
|
|
22402
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
22403
|
+
promise2.then(
|
|
22404
|
+
(value) => {
|
|
22405
|
+
signal.removeEventListener("abort", onAbort);
|
|
22406
|
+
resolve6(value);
|
|
22407
|
+
},
|
|
22408
|
+
(error40) => {
|
|
22409
|
+
signal.removeEventListener("abort", onAbort);
|
|
22410
|
+
reject(error40);
|
|
22411
|
+
}
|
|
22412
|
+
);
|
|
22413
|
+
});
|
|
22414
|
+
}
|
|
22415
|
+
async function waitForRetry(waitMs, signal) {
|
|
22416
|
+
if (!signal) {
|
|
22353
22417
|
await new Promise((resolve6) => setTimeout(resolve6, waitMs));
|
|
22354
|
-
return
|
|
22418
|
+
return;
|
|
22355
22419
|
}
|
|
22356
|
-
const
|
|
22357
|
-
throw new Error(
|
|
22420
|
+
const abortSignal = signal;
|
|
22421
|
+
if (abortSignal.aborted) throw new Error("Embedding API retry aborted");
|
|
22422
|
+
await new Promise((resolve6, reject) => {
|
|
22423
|
+
const timer = setTimeout(done, waitMs);
|
|
22424
|
+
const onAbort = () => {
|
|
22425
|
+
clearTimeout(timer);
|
|
22426
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
22427
|
+
reject(new Error("Embedding API retry aborted"));
|
|
22428
|
+
};
|
|
22429
|
+
function done() {
|
|
22430
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
22431
|
+
resolve6();
|
|
22432
|
+
}
|
|
22433
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
22434
|
+
});
|
|
22358
22435
|
}
|
|
22359
|
-
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;
|
|
22436
|
+
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;
|
|
22360
22437
|
var init_api_provider = __esm({
|
|
22361
22438
|
"src/embedding/api-provider.ts"() {
|
|
22362
22439
|
"use strict";
|
|
@@ -22375,6 +22452,14 @@ var init_api_provider = __esm({
|
|
|
22375
22452
|
DASHSCOPE_MAX_BATCH_SIZE = 10;
|
|
22376
22453
|
MAX_RETRIES2 = 3;
|
|
22377
22454
|
BASE_DELAY_MS = 500;
|
|
22455
|
+
EmbeddingAPIError = class extends Error {
|
|
22456
|
+
status;
|
|
22457
|
+
constructor(status, detail) {
|
|
22458
|
+
super(`Embedding API error (${status}): ${detail}`);
|
|
22459
|
+
this.name = "EmbeddingAPIError";
|
|
22460
|
+
this.status = status;
|
|
22461
|
+
}
|
|
22462
|
+
};
|
|
22378
22463
|
APIEmbeddingProvider = class _APIEmbeddingProvider {
|
|
22379
22464
|
name;
|
|
22380
22465
|
dimensions;
|
|
@@ -22586,15 +22671,14 @@ var init_api_provider = __esm({
|
|
|
22586
22671
|
}
|
|
22587
22672
|
} catch (error40) {
|
|
22588
22673
|
const providerLimit = parseBatchLimit(error40);
|
|
22589
|
-
|
|
22590
|
-
if (chunkTexts.length > 1 && fallbackSize < chunkTexts.length) {
|
|
22674
|
+
if (providerLimit !== null && chunkTexts.length > 1 && providerLimit < chunkTexts.length) {
|
|
22591
22675
|
console.error(
|
|
22592
|
-
`[memorix] Embedding batch too large for provider, retrying in chunks of ${
|
|
22676
|
+
`[memorix] Embedding batch too large for provider, retrying in chunks of ${providerLimit}`
|
|
22593
22677
|
);
|
|
22594
|
-
for (let start = 0; start < chunkTexts.length; start +=
|
|
22678
|
+
for (let start = 0; start < chunkTexts.length; start += providerLimit) {
|
|
22595
22679
|
await processChunk(
|
|
22596
|
-
chunkTexts.slice(start, start +
|
|
22597
|
-
chunkIndices.slice(start, start +
|
|
22680
|
+
chunkTexts.slice(start, start + providerLimit),
|
|
22681
|
+
chunkIndices.slice(start, start + providerLimit)
|
|
22598
22682
|
);
|
|
22599
22683
|
}
|
|
22600
22684
|
return;
|
|
@@ -23458,22 +23542,23 @@ function getLLMConfig() {
|
|
|
23458
23542
|
function setLLMConfig(config2) {
|
|
23459
23543
|
currentConfig = config2;
|
|
23460
23544
|
}
|
|
23461
|
-
async function callLLM(systemPrompt, userMessage) {
|
|
23545
|
+
async function callLLM(systemPrompt, userMessage, signal) {
|
|
23462
23546
|
if (!currentConfig) {
|
|
23463
23547
|
throw new Error("LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.");
|
|
23464
23548
|
}
|
|
23465
23549
|
if (currentConfig.provider === "anthropic") {
|
|
23466
|
-
return callAnthropic(systemPrompt, userMessage);
|
|
23550
|
+
return callAnthropic(systemPrompt, userMessage, signal);
|
|
23467
23551
|
}
|
|
23468
|
-
return callOpenAICompatible(systemPrompt, userMessage);
|
|
23552
|
+
return callOpenAICompatible(systemPrompt, userMessage, signal);
|
|
23469
23553
|
}
|
|
23470
|
-
async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
23554
|
+
async function callOpenAICompatible(systemPrompt, userMessage, signal) {
|
|
23471
23555
|
const config2 = currentConfig;
|
|
23472
23556
|
let base = config2.baseUrl.replace(/\/+$/, "");
|
|
23473
23557
|
if (!base.endsWith("/v1")) base += "/v1";
|
|
23474
23558
|
const url2 = `${base}/chat/completions`;
|
|
23559
|
+
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
23475
23560
|
const response = await fetch(url2, {
|
|
23476
|
-
signal:
|
|
23561
|
+
signal: fetchSignal,
|
|
23477
23562
|
method: "POST",
|
|
23478
23563
|
headers: {
|
|
23479
23564
|
"Content-Type": "application/json",
|
|
@@ -23490,10 +23575,10 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
|
23490
23575
|
})
|
|
23491
23576
|
});
|
|
23492
23577
|
if (!response.ok) {
|
|
23493
|
-
const error40 = await readResponseText(response,
|
|
23578
|
+
const error40 = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
|
|
23494
23579
|
throw new Error(`LLM API error (${response.status}): ${error40}`);
|
|
23495
23580
|
}
|
|
23496
|
-
const data = await readResponseJson(response);
|
|
23581
|
+
const data = await readResponseJson(response, signal);
|
|
23497
23582
|
return {
|
|
23498
23583
|
content: data.choices[0]?.message?.content ?? "",
|
|
23499
23584
|
usage: data.usage ? {
|
|
@@ -23502,11 +23587,12 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
|
23502
23587
|
} : void 0
|
|
23503
23588
|
};
|
|
23504
23589
|
}
|
|
23505
|
-
async function callAnthropic(systemPrompt, userMessage) {
|
|
23590
|
+
async function callAnthropic(systemPrompt, userMessage, signal) {
|
|
23506
23591
|
const config2 = currentConfig;
|
|
23507
23592
|
const url2 = `${config2.baseUrl}/messages`;
|
|
23593
|
+
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
23508
23594
|
const response = await fetch(url2, {
|
|
23509
|
-
signal:
|
|
23595
|
+
signal: fetchSignal,
|
|
23510
23596
|
method: "POST",
|
|
23511
23597
|
headers: {
|
|
23512
23598
|
"Content-Type": "application/json",
|
|
@@ -23524,10 +23610,10 @@ async function callAnthropic(systemPrompt, userMessage) {
|
|
|
23524
23610
|
})
|
|
23525
23611
|
});
|
|
23526
23612
|
if (!response.ok) {
|
|
23527
|
-
const error40 = await readResponseText(response,
|
|
23613
|
+
const error40 = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
|
|
23528
23614
|
throw new Error(`Anthropic API error (${response.status}): ${error40}`);
|
|
23529
23615
|
}
|
|
23530
|
-
const data = await readResponseJson(response);
|
|
23616
|
+
const data = await readResponseJson(response, signal);
|
|
23531
23617
|
return {
|
|
23532
23618
|
content: data.content[0]?.text ?? "",
|
|
23533
23619
|
usage: data.usage ? {
|
|
@@ -24032,6 +24118,57 @@ function withTimeout(promise2, ms2, label) {
|
|
|
24032
24118
|
);
|
|
24033
24119
|
});
|
|
24034
24120
|
}
|
|
24121
|
+
function withTimeoutSignal(operation, ms2, label, parentSignal) {
|
|
24122
|
+
const controller = new AbortController();
|
|
24123
|
+
const signal = parentSignal ? AbortSignal.any([parentSignal, controller.signal]) : controller.signal;
|
|
24124
|
+
return new Promise((resolve6, reject) => {
|
|
24125
|
+
let settled = false;
|
|
24126
|
+
let timedOut = false;
|
|
24127
|
+
let timer;
|
|
24128
|
+
const cleanup = () => {
|
|
24129
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
24130
|
+
parentSignal?.removeEventListener("abort", onParentAbort);
|
|
24131
|
+
};
|
|
24132
|
+
const onParentAbort = () => {
|
|
24133
|
+
if (settled || timedOut) return;
|
|
24134
|
+
settled = true;
|
|
24135
|
+
cleanup();
|
|
24136
|
+
reject(parentSignal?.reason ?? new Error(`${label} aborted`));
|
|
24137
|
+
};
|
|
24138
|
+
parentSignal?.addEventListener("abort", onParentAbort, { once: true });
|
|
24139
|
+
timer = setTimeout(() => {
|
|
24140
|
+
if (settled) return;
|
|
24141
|
+
timedOut = true;
|
|
24142
|
+
controller.abort(new Error(`${label} timed out after ${ms2}ms`));
|
|
24143
|
+
settled = true;
|
|
24144
|
+
cleanup();
|
|
24145
|
+
reject(new Error(`${label} timed out after ${ms2}ms`));
|
|
24146
|
+
}, ms2);
|
|
24147
|
+
let pending;
|
|
24148
|
+
try {
|
|
24149
|
+
pending = operation(signal);
|
|
24150
|
+
} catch (error40) {
|
|
24151
|
+
settled = true;
|
|
24152
|
+
cleanup();
|
|
24153
|
+
reject(error40);
|
|
24154
|
+
return;
|
|
24155
|
+
}
|
|
24156
|
+
pending.then(
|
|
24157
|
+
(value) => {
|
|
24158
|
+
if (settled) return;
|
|
24159
|
+
settled = true;
|
|
24160
|
+
cleanup();
|
|
24161
|
+
resolve6(value);
|
|
24162
|
+
},
|
|
24163
|
+
(error40) => {
|
|
24164
|
+
if (settled) return;
|
|
24165
|
+
settled = true;
|
|
24166
|
+
cleanup();
|
|
24167
|
+
reject(timedOut ? new Error(`${label} timed out after ${ms2}ms`) : error40);
|
|
24168
|
+
}
|
|
24169
|
+
);
|
|
24170
|
+
});
|
|
24171
|
+
}
|
|
24035
24172
|
var init_timeout = __esm({
|
|
24036
24173
|
"src/timeout.ts"() {
|
|
24037
24174
|
"use strict";
|
|
@@ -178207,7 +178344,13 @@ async function maintainLongTermMemories(input) {
|
|
|
178207
178344
|
}
|
|
178208
178345
|
for (const group of groups.values()) {
|
|
178209
178346
|
if (group.length < 2) continue;
|
|
178210
|
-
group.sort((a4, b4) =>
|
|
178347
|
+
group.sort((a4, b4) => {
|
|
178348
|
+
const byCreatedAt = Date.parse(b4.createdAt) - Date.parse(a4.createdAt);
|
|
178349
|
+
if (byCreatedAt !== 0) return byCreatedAt;
|
|
178350
|
+
const byUpdatedAt = Date.parse(b4.updatedAt) - Date.parse(a4.updatedAt);
|
|
178351
|
+
if (byUpdatedAt !== 0) return byUpdatedAt;
|
|
178352
|
+
return b4.id.localeCompare(a4.id);
|
|
178353
|
+
});
|
|
178211
178354
|
const newest = group[0];
|
|
178212
178355
|
for (const older of group.slice(1)) {
|
|
178213
178356
|
try {
|
|
@@ -184723,16 +184866,18 @@ async function searchObservations(options) {
|
|
|
184723
184866
|
);
|
|
184724
184867
|
} else {
|
|
184725
184868
|
const EMBEDDING_TIMEOUT_MS = 15e3;
|
|
184726
|
-
queryVector = await
|
|
184727
|
-
provider2.embedInput ? provider2.embedInput(
|
|
184869
|
+
queryVector = await withTimeoutSignal(
|
|
184870
|
+
(signal) => provider2.embedInput ? provider2.embedInput(
|
|
184728
184871
|
{ modality: "text", text: expandedEmbeddingQuery },
|
|
184729
|
-
{ intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false }
|
|
184872
|
+
{ intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false, signal }
|
|
184730
184873
|
) : provider2.embed(expandedEmbeddingQuery, {
|
|
184731
184874
|
timeoutMs: EMBEDDING_TIMEOUT_MS,
|
|
184732
|
-
retry: false
|
|
184875
|
+
retry: false,
|
|
184876
|
+
signal
|
|
184733
184877
|
}),
|
|
184734
184878
|
EMBEDDING_TIMEOUT_MS,
|
|
184735
|
-
"Embedding"
|
|
184879
|
+
"Embedding",
|
|
184880
|
+
options.signal
|
|
184736
184881
|
);
|
|
184737
184882
|
mark("embedding");
|
|
184738
184883
|
const cjkRatio = (originalQuery.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length / originalQuery.length;
|
|
@@ -199192,13 +199337,13 @@ function verifyType(declaredType, narrative, title) {
|
|
|
199192
199337
|
}
|
|
199193
199338
|
return { type: declaredType, corrected: false };
|
|
199194
199339
|
}
|
|
199195
|
-
async function extractFactsWithLLM(narrative, title, existingFacts) {
|
|
199340
|
+
async function extractFactsWithLLM(narrative, title, existingFacts, signal) {
|
|
199196
199341
|
try {
|
|
199197
199342
|
const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
199198
199343
|
const input = `Title: ${title}
|
|
199199
199344
|
Content: ${narrative}${existingFacts.length > 0 ? `
|
|
199200
199345
|
Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
|
|
199201
|
-
const response = await callLLM2(LLM_EXTRACT_PROMPT, input);
|
|
199346
|
+
const response = await callLLM2(LLM_EXTRACT_PROMPT, input, signal);
|
|
199202
199347
|
const text2 = response.content.trim();
|
|
199203
199348
|
const jsonMatch = text2.match(/\{[\s\S]*\}/);
|
|
199204
199349
|
if (!jsonMatch) return [];
|
|
@@ -199207,15 +199352,16 @@ Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
|
|
|
199207
199352
|
if (!Array.isArray(facts)) return [];
|
|
199208
199353
|
const existingLower = new Set(existingFacts.map((f7) => f7.toLowerCase().trim()));
|
|
199209
199354
|
return facts.filter((f7) => typeof f7 === "string" && f7.length >= 5).filter((f7) => !existingLower.has(f7.toLowerCase().trim())).slice(0, 10);
|
|
199210
|
-
} catch {
|
|
199355
|
+
} catch (error40) {
|
|
199356
|
+
if (signal?.aborted) throw error40;
|
|
199211
199357
|
return [];
|
|
199212
199358
|
}
|
|
199213
199359
|
}
|
|
199214
|
-
async function runExtract(input, existingEntities, useLLM = false) {
|
|
199360
|
+
async function runExtract(input, existingEntities, useLLM = false, signal) {
|
|
199215
199361
|
const callerFacts = input.facts ?? [];
|
|
199216
199362
|
let extractedFacts;
|
|
199217
199363
|
if (useLLM) {
|
|
199218
|
-
extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts);
|
|
199364
|
+
extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts, signal);
|
|
199219
199365
|
if (extractedFacts.length === 0) {
|
|
199220
199366
|
extractedFacts = extractFacts2(input.narrative, callerFacts);
|
|
199221
199367
|
}
|
|
@@ -199435,7 +199581,7 @@ function mergeFacts2(oldFacts, newFacts) {
|
|
|
199435
199581
|
}
|
|
199436
199582
|
return merged;
|
|
199437
199583
|
}
|
|
199438
|
-
async function resolveWithLLM(extracted, hits, getObservation2) {
|
|
199584
|
+
async function resolveWithLLM(extracted, hits, getObservation2, signal) {
|
|
199439
199585
|
try {
|
|
199440
199586
|
const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
199441
199587
|
const existingMemories = hits.slice(0, 5).map((h5, i4) => ({
|
|
@@ -199452,7 +199598,7 @@ Facts: ${extracted.facts.join("; ")}
|
|
|
199452
199598
|
|
|
199453
199599
|
EXISTING MEMORIES:
|
|
199454
199600
|
${existingMemories.map((m6) => `[ID:${m6.id}] ${m6.title} | ${m6.content} | Facts: ${m6.facts}`).join("\n")}`;
|
|
199455
|
-
const response = await callLLM2(LLM_RESOLVE_PROMPT, input);
|
|
199601
|
+
const response = await callLLM2(LLM_RESOLVE_PROMPT, input, signal);
|
|
199456
199602
|
const text2 = response.content.trim();
|
|
199457
199603
|
const jsonMatch = text2.match(/\{[\s\S]*\}/);
|
|
199458
199604
|
if (!jsonMatch) return null;
|
|
@@ -199489,7 +199635,8 @@ ${existingMemories.map((m6) => `[ID:${m6.id}] ${m6.title} | ${m6.content} | Fact
|
|
|
199489
199635
|
};
|
|
199490
199636
|
}
|
|
199491
199637
|
return null;
|
|
199492
|
-
} catch {
|
|
199638
|
+
} catch (error40) {
|
|
199639
|
+
if (signal?.aborted) throw error40;
|
|
199493
199640
|
return null;
|
|
199494
199641
|
}
|
|
199495
199642
|
}
|
|
@@ -199507,19 +199654,20 @@ function scoreCandidate(extracted, candidate2) {
|
|
|
199507
199654
|
const contradiction = hasContradiction(candidate2.narrative, extracted.narrative);
|
|
199508
199655
|
return { score, searchSimilarity, entityMatch, richer, contradiction };
|
|
199509
199656
|
}
|
|
199510
|
-
async function runResolve(extracted, projectId, searchMemories3, getObservation2, useLLM = false) {
|
|
199657
|
+
async function runResolve(extracted, projectId, searchMemories3, getObservation2, useLLM = false, signal) {
|
|
199511
199658
|
const query = `${extracted.title} ${extracted.narrative.substring(0, 200)}`;
|
|
199512
199659
|
let hits;
|
|
199513
199660
|
try {
|
|
199514
|
-
hits = await searchMemories3(query, 5, projectId);
|
|
199515
|
-
} catch {
|
|
199661
|
+
hits = await searchMemories3(query, 5, projectId, signal);
|
|
199662
|
+
} catch (error40) {
|
|
199663
|
+
if (signal?.aborted) throw error40;
|
|
199516
199664
|
return { action: "new", reason: "Search unavailable, defaulting to new" };
|
|
199517
199665
|
}
|
|
199518
199666
|
if (hits.length === 0) {
|
|
199519
199667
|
return { action: "new", reason: "No similar existing memories found" };
|
|
199520
199668
|
}
|
|
199521
199669
|
if (useLLM) {
|
|
199522
|
-
const llmResult = await resolveWithLLM(extracted, hits, getObservation2);
|
|
199670
|
+
const llmResult = await resolveWithLLM(extracted, hits, getObservation2, signal);
|
|
199523
199671
|
if (llmResult) return llmResult;
|
|
199524
199672
|
}
|
|
199525
199673
|
const scored = hits.map((hit) => ({
|
|
@@ -199941,7 +200089,7 @@ async function runFormation(input, config2) {
|
|
|
199941
200089
|
const existingEntities = config2.getEntityNames();
|
|
199942
200090
|
const extractStartTime = Date.now();
|
|
199943
200091
|
emitStageEvent("extract", "start");
|
|
199944
|
-
const extraction = await runExtract(input, existingEntities, config2.useLLM);
|
|
200092
|
+
const extraction = await runExtract(input, existingEntities, config2.useLLM, config2.signal);
|
|
199945
200093
|
stageDurationsMs.extract = Date.now() - extractStartTime;
|
|
199946
200094
|
emitStageEvent("extract", "success", stageDurationsMs.extract);
|
|
199947
200095
|
stagesCompleted = 1;
|
|
@@ -199961,7 +200109,8 @@ async function runFormation(input, config2) {
|
|
|
199961
200109
|
input.projectId,
|
|
199962
200110
|
config2.searchMemories,
|
|
199963
200111
|
config2.getObservation,
|
|
199964
|
-
config2.useLLM
|
|
200112
|
+
config2.useLLM,
|
|
200113
|
+
config2.signal
|
|
199965
200114
|
);
|
|
199966
200115
|
stageDurationsMs.resolve = Date.now() - resolveStartTime;
|
|
199967
200116
|
emitStageEvent("resolve", "success", stageDurationsMs.resolve);
|
|
@@ -258695,7 +258844,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
258695
258844
|
};
|
|
258696
258845
|
const server = existingServer ?? new McpServer({
|
|
258697
258846
|
name: "memorix",
|
|
258698
|
-
version: true ? "1.
|
|
258847
|
+
version: true ? "1.5.1" : "1.0.1"
|
|
258699
258848
|
});
|
|
258700
258849
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
258701
258850
|
server.registerTool = ((name, ...args) => {
|
|
@@ -258884,8 +259033,8 @@ The path should point to a directory containing a .git folder.`
|
|
|
258884
259033
|
mode: "active",
|
|
258885
259034
|
useLLM: isLLMEnabled(),
|
|
258886
259035
|
minValueScore: 0.3,
|
|
258887
|
-
searchMemories: async (q4, limit2, pid) => {
|
|
258888
|
-
const result = await compactSearch({ query: q4, limit: limit2, projectId: pid, status: "active", reader });
|
|
259036
|
+
searchMemories: async (q4, limit2, pid, signal) => {
|
|
259037
|
+
const result = await compactSearch({ query: q4, limit: limit2, projectId: pid, status: "active", reader, signal });
|
|
258889
259038
|
if (result.entries.length === 0) return [];
|
|
258890
259039
|
const details = await compactDetail(result.entries.map((e5) => e5.id), { reader });
|
|
258891
259040
|
return details.documents.map((d4, i4) => ({
|
|
@@ -258915,16 +259064,19 @@ The path should point to a directory containing a .git folder.`
|
|
|
258915
259064
|
getEntityNames: () => graphManager.getEntityNames(),
|
|
258916
259065
|
onStageEvent: onFormationStageEvent
|
|
258917
259066
|
};
|
|
258918
|
-
formationResult = await
|
|
258919
|
-
|
|
258920
|
-
|
|
258921
|
-
|
|
258922
|
-
|
|
258923
|
-
|
|
258924
|
-
|
|
258925
|
-
|
|
258926
|
-
|
|
258927
|
-
|
|
259067
|
+
formationResult = await withTimeoutSignal(
|
|
259068
|
+
async (signal) => {
|
|
259069
|
+
formationConfig.signal = signal;
|
|
259070
|
+
return runFormation({
|
|
259071
|
+
entityName,
|
|
259072
|
+
type,
|
|
259073
|
+
title,
|
|
259074
|
+
narrative,
|
|
259075
|
+
facts: safeFacts,
|
|
259076
|
+
projectId: project.id,
|
|
259077
|
+
source: "explicit"
|
|
259078
|
+
}, formationConfig);
|
|
259079
|
+
},
|
|
258928
259080
|
FORMATION_TIMEOUT_MS,
|
|
258929
259081
|
"Formation pipeline"
|
|
258930
259082
|
);
|
|
@@ -259274,8 +259426,8 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
259274
259426
|
mode: formationMode,
|
|
259275
259427
|
useLLM: isLLMEnabled(),
|
|
259276
259428
|
minValueScore: 0.3,
|
|
259277
|
-
searchMemories: async (q4, limit2, pid) => {
|
|
259278
|
-
const result = await compactSearch({ query: q4, limit: limit2, projectId: pid, status: "active", reader });
|
|
259429
|
+
searchMemories: async (q4, limit2, pid, signal) => {
|
|
259430
|
+
const result = await compactSearch({ query: q4, limit: limit2, projectId: pid, status: "active", reader, signal });
|
|
259279
259431
|
if (result.entries.length === 0) return [];
|
|
259280
259432
|
const details = await compactDetail(result.entries.map((e5) => e5.id), { reader });
|
|
259281
259433
|
return details.documents.map((d4, i4) => ({
|
|
@@ -259296,8 +259448,11 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
259296
259448
|
},
|
|
259297
259449
|
getEntityNames: () => graphManager.getEntityNames()
|
|
259298
259450
|
};
|
|
259299
|
-
const formed = await
|
|
259300
|
-
|
|
259451
|
+
const formed = await withTimeoutSignal(
|
|
259452
|
+
async (signal) => {
|
|
259453
|
+
formationConfig.signal = signal;
|
|
259454
|
+
return runFormation({ entityName, type, title, narrative, facts: safeFacts, projectId: project.id, source: "explicit", topicKey }, formationConfig);
|
|
259455
|
+
},
|
|
259301
259456
|
FORMATION_TIMEOUT_MS,
|
|
259302
259457
|
"Shadow formation"
|
|
259303
259458
|
);
|
package/dist/cli/memcode.js
CHANGED
|
File without changes
|