memorix 1.5.0 → 1.6.0
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 +37 -0
- package/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/dist/cli/index.js +452 -109
- package/dist/index.js +376 -87
- package/dist/maintenance-runner.js +174 -41
- package/dist/media-audio-runner.js +174 -41
- package/dist/media-video-runner.js +174 -41
- package/dist/memcode-runtime/CHANGELOG.md +37 -0
- package/dist/sdk.js +375 -86
- package/dist/types.d.ts +2 -0
- package/dist/vector-backfill-runner.js +174 -41
- package/docs/1.2.4-PERSISTENT-MEMORY-DELIVERY.md +1 -1
- package/docs/API_REFERENCE.md +1 -1
- package/docs/DEVELOPMENT.md +5 -3
- package/package.json +1 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/cli/commands/codegraph.ts +48 -5
- package/src/cli/commands/context.ts +20 -4
- package/src/cli/commands/resume.ts +4 -0
- package/src/codegraph/auto-context.ts +4 -1
- package/src/codegraph/context-pack.ts +3 -1
- package/src/codegraph/external-provider.ts +93 -0
- package/src/embedding/api-provider.ts +105 -22
- package/src/embedding/provider.ts +2 -0
- package/src/hooks/installers/index.ts +1 -1
- package/src/hooks/official-skills.ts +3 -3
- package/src/hooks/rules/memorix-agent-rules.md +1 -1
- package/src/knowledge/context-receipt.ts +41 -0
- package/src/knowledge/workflows.ts +6 -3
- package/src/knowledge/workset.ts +56 -2
- package/src/llm/provider.ts +17 -8
- 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/long-term.ts +7 -1
- package/src/server.ts +29 -13
- package/src/store/orama-store.ts +6 -4
- package/src/timeout.ts +67 -0
- package/src/types.ts +2 -0
package/dist/sdk.js
CHANGED
|
@@ -3991,6 +3991,8 @@ function getPreferredBatchSize(config) {
|
|
|
3991
3991
|
}
|
|
3992
3992
|
function parseBatchLimit(error) {
|
|
3993
3993
|
if (!(error instanceof Error)) return null;
|
|
3994
|
+
const status = error instanceof EmbeddingAPIError ? error.status : Number(error.message.match(/Embedding API error \((\d{3})\)/i)?.[1] ?? 0);
|
|
3995
|
+
if (status > 0 && status !== 400) return null;
|
|
3994
3996
|
const explicit = error.message.match(/should not be larger than\s+(\d+)/i);
|
|
3995
3997
|
if (explicit) return parseInt(explicit[1], 10);
|
|
3996
3998
|
if (/batch size/i.test(error.message)) {
|
|
@@ -4003,37 +4005,99 @@ async function fetchWithRetry(url, apiKey, body, options = {}, attempt = 0, nati
|
|
|
4003
4005
|
const controller = new AbortController();
|
|
4004
4006
|
const timeoutMs = typeof options.timeoutMs === "number" && Number.isFinite(options.timeoutMs) ? Math.max(100, Math.min(Math.floor(options.timeoutMs), 6e4)) : 1e4;
|
|
4005
4007
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
4008
|
+
const signal = options.signal ? AbortSignal.any([options.signal, controller.signal]) : controller.signal;
|
|
4006
4009
|
let response;
|
|
4007
4010
|
try {
|
|
4008
4011
|
response = await fetch(url, {
|
|
4009
4012
|
method: "POST",
|
|
4010
4013
|
headers: nativeGemini ? { "Content-Type": "application/json", "x-goog-api-key": apiKey } : { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` },
|
|
4011
4014
|
body: JSON.stringify(body),
|
|
4012
|
-
signal
|
|
4015
|
+
signal
|
|
4013
4016
|
});
|
|
4014
4017
|
} catch (err) {
|
|
4015
4018
|
clearTimeout(timeout);
|
|
4016
|
-
if (err instanceof Error && err.name === "AbortError") {
|
|
4019
|
+
if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
|
|
4017
4020
|
throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url}`);
|
|
4018
4021
|
}
|
|
4019
4022
|
throw err;
|
|
4020
4023
|
}
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
+
try {
|
|
4025
|
+
if (response.ok) {
|
|
4026
|
+
return await raceWithAbort(
|
|
4027
|
+
response.json(),
|
|
4028
|
+
signal
|
|
4029
|
+
);
|
|
4030
|
+
}
|
|
4031
|
+
if (options.retry !== false && (response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES2) {
|
|
4032
|
+
const delay2 = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
4033
|
+
const retryAfter = response.headers.get("retry-after");
|
|
4034
|
+
const parsedRetryAfter = retryAfter ? parseInt(retryAfter, 10) * 1e3 : NaN;
|
|
4035
|
+
const waitMs = Number.isFinite(parsedRetryAfter) ? parsedRetryAfter : delay2;
|
|
4036
|
+
console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES2} in ${waitMs}ms`);
|
|
4037
|
+
await waitForRetry(waitMs, options.signal);
|
|
4038
|
+
return fetchWithRetry(url, apiKey, body, options, attempt + 1, nativeGemini);
|
|
4039
|
+
}
|
|
4040
|
+
const errorText2 = await raceWithAbort(
|
|
4041
|
+
response.text().catch(() => "unknown error"),
|
|
4042
|
+
signal
|
|
4043
|
+
);
|
|
4044
|
+
throw new EmbeddingAPIError(response.status, errorText2);
|
|
4045
|
+
} catch (err) {
|
|
4046
|
+
if (err instanceof Error && (err.name === "AbortError" || controller.signal.aborted || options.signal?.aborted)) {
|
|
4047
|
+
throw new Error(`Embedding API timeout after ${timeoutMs}ms: ${url}`);
|
|
4048
|
+
}
|
|
4049
|
+
throw err;
|
|
4050
|
+
} finally {
|
|
4051
|
+
clearTimeout(timeout);
|
|
4024
4052
|
}
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4053
|
+
}
|
|
4054
|
+
function abortError() {
|
|
4055
|
+
const error = new Error("Embedding API request aborted");
|
|
4056
|
+
error.name = "AbortError";
|
|
4057
|
+
return error;
|
|
4058
|
+
}
|
|
4059
|
+
function raceWithAbort(promise, signal) {
|
|
4060
|
+
if (signal.aborted) return Promise.reject(abortError());
|
|
4061
|
+
return new Promise((resolve2, reject) => {
|
|
4062
|
+
const onAbort = () => {
|
|
4063
|
+
signal.removeEventListener("abort", onAbort);
|
|
4064
|
+
reject(abortError());
|
|
4065
|
+
};
|
|
4066
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
4067
|
+
promise.then(
|
|
4068
|
+
(value) => {
|
|
4069
|
+
signal.removeEventListener("abort", onAbort);
|
|
4070
|
+
resolve2(value);
|
|
4071
|
+
},
|
|
4072
|
+
(error) => {
|
|
4073
|
+
signal.removeEventListener("abort", onAbort);
|
|
4074
|
+
reject(error);
|
|
4075
|
+
}
|
|
4076
|
+
);
|
|
4077
|
+
});
|
|
4078
|
+
}
|
|
4079
|
+
async function waitForRetry(waitMs, signal) {
|
|
4080
|
+
if (!signal) {
|
|
4030
4081
|
await new Promise((resolve2) => setTimeout(resolve2, waitMs));
|
|
4031
|
-
return
|
|
4082
|
+
return;
|
|
4032
4083
|
}
|
|
4033
|
-
const
|
|
4034
|
-
throw new Error(
|
|
4084
|
+
const abortSignal = signal;
|
|
4085
|
+
if (abortSignal.aborted) throw new Error("Embedding API retry aborted");
|
|
4086
|
+
await new Promise((resolve2, reject) => {
|
|
4087
|
+
const timer = setTimeout(done, waitMs);
|
|
4088
|
+
const onAbort = () => {
|
|
4089
|
+
clearTimeout(timer);
|
|
4090
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
4091
|
+
reject(new Error("Embedding API retry aborted"));
|
|
4092
|
+
};
|
|
4093
|
+
function done() {
|
|
4094
|
+
abortSignal.removeEventListener("abort", onAbort);
|
|
4095
|
+
resolve2();
|
|
4096
|
+
}
|
|
4097
|
+
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
4098
|
+
});
|
|
4035
4099
|
}
|
|
4036
|
-
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;
|
|
4100
|
+
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;
|
|
4037
4101
|
var init_api_provider = __esm({
|
|
4038
4102
|
"src/embedding/api-provider.ts"() {
|
|
4039
4103
|
"use strict";
|
|
@@ -4052,6 +4116,14 @@ var init_api_provider = __esm({
|
|
|
4052
4116
|
DASHSCOPE_MAX_BATCH_SIZE = 10;
|
|
4053
4117
|
MAX_RETRIES2 = 3;
|
|
4054
4118
|
BASE_DELAY_MS = 500;
|
|
4119
|
+
EmbeddingAPIError = class extends Error {
|
|
4120
|
+
status;
|
|
4121
|
+
constructor(status, detail) {
|
|
4122
|
+
super(`Embedding API error (${status}): ${detail}`);
|
|
4123
|
+
this.name = "EmbeddingAPIError";
|
|
4124
|
+
this.status = status;
|
|
4125
|
+
}
|
|
4126
|
+
};
|
|
4055
4127
|
APIEmbeddingProvider = class _APIEmbeddingProvider {
|
|
4056
4128
|
name;
|
|
4057
4129
|
dimensions;
|
|
@@ -4263,15 +4335,14 @@ var init_api_provider = __esm({
|
|
|
4263
4335
|
}
|
|
4264
4336
|
} catch (error) {
|
|
4265
4337
|
const providerLimit = parseBatchLimit(error);
|
|
4266
|
-
|
|
4267
|
-
if (chunkTexts.length > 1 && fallbackSize < chunkTexts.length) {
|
|
4338
|
+
if (providerLimit !== null && chunkTexts.length > 1 && providerLimit < chunkTexts.length) {
|
|
4268
4339
|
console.error(
|
|
4269
|
-
`[memorix] Embedding batch too large for provider, retrying in chunks of ${
|
|
4340
|
+
`[memorix] Embedding batch too large for provider, retrying in chunks of ${providerLimit}`
|
|
4270
4341
|
);
|
|
4271
|
-
for (let start = 0; start < chunkTexts.length; start +=
|
|
4342
|
+
for (let start = 0; start < chunkTexts.length; start += providerLimit) {
|
|
4272
4343
|
await processChunk(
|
|
4273
|
-
chunkTexts.slice(start, start +
|
|
4274
|
-
chunkIndices.slice(start, start +
|
|
4344
|
+
chunkTexts.slice(start, start + providerLimit),
|
|
4345
|
+
chunkIndices.slice(start, start + providerLimit)
|
|
4275
4346
|
);
|
|
4276
4347
|
}
|
|
4277
4348
|
return;
|
|
@@ -5135,22 +5206,23 @@ function getLLMConfig() {
|
|
|
5135
5206
|
function setLLMConfig(config) {
|
|
5136
5207
|
currentConfig = config;
|
|
5137
5208
|
}
|
|
5138
|
-
async function callLLM(systemPrompt, userMessage) {
|
|
5209
|
+
async function callLLM(systemPrompt, userMessage, signal) {
|
|
5139
5210
|
if (!currentConfig) {
|
|
5140
5211
|
throw new Error("LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.");
|
|
5141
5212
|
}
|
|
5142
5213
|
if (currentConfig.provider === "anthropic") {
|
|
5143
|
-
return callAnthropic(systemPrompt, userMessage);
|
|
5214
|
+
return callAnthropic(systemPrompt, userMessage, signal);
|
|
5144
5215
|
}
|
|
5145
|
-
return callOpenAICompatible(systemPrompt, userMessage);
|
|
5216
|
+
return callOpenAICompatible(systemPrompt, userMessage, signal);
|
|
5146
5217
|
}
|
|
5147
|
-
async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
5218
|
+
async function callOpenAICompatible(systemPrompt, userMessage, signal) {
|
|
5148
5219
|
const config = currentConfig;
|
|
5149
5220
|
let base = config.baseUrl.replace(/\/+$/, "");
|
|
5150
5221
|
if (!base.endsWith("/v1")) base += "/v1";
|
|
5151
5222
|
const url = `${base}/chat/completions`;
|
|
5223
|
+
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
5152
5224
|
const response = await fetch(url, {
|
|
5153
|
-
signal:
|
|
5225
|
+
signal: fetchSignal,
|
|
5154
5226
|
method: "POST",
|
|
5155
5227
|
headers: {
|
|
5156
5228
|
"Content-Type": "application/json",
|
|
@@ -5167,10 +5239,10 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
|
5167
5239
|
})
|
|
5168
5240
|
});
|
|
5169
5241
|
if (!response.ok) {
|
|
5170
|
-
const error = await readResponseText(response,
|
|
5242
|
+
const error = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
|
|
5171
5243
|
throw new Error(`LLM API error (${response.status}): ${error}`);
|
|
5172
5244
|
}
|
|
5173
|
-
const data = await readResponseJson(response);
|
|
5245
|
+
const data = await readResponseJson(response, signal);
|
|
5174
5246
|
return {
|
|
5175
5247
|
content: data.choices[0]?.message?.content ?? "",
|
|
5176
5248
|
usage: data.usage ? {
|
|
@@ -5179,11 +5251,12 @@ async function callOpenAICompatible(systemPrompt, userMessage) {
|
|
|
5179
5251
|
} : void 0
|
|
5180
5252
|
};
|
|
5181
5253
|
}
|
|
5182
|
-
async function callAnthropic(systemPrompt, userMessage) {
|
|
5254
|
+
async function callAnthropic(systemPrompt, userMessage, signal) {
|
|
5183
5255
|
const config = currentConfig;
|
|
5184
5256
|
const url = `${config.baseUrl}/messages`;
|
|
5257
|
+
const fetchSignal = signal ? AbortSignal.any([signal, AbortSignal.timeout(LLM_CALL_TIMEOUT_MS)]) : AbortSignal.timeout(LLM_CALL_TIMEOUT_MS);
|
|
5185
5258
|
const response = await fetch(url, {
|
|
5186
|
-
signal:
|
|
5259
|
+
signal: fetchSignal,
|
|
5187
5260
|
method: "POST",
|
|
5188
5261
|
headers: {
|
|
5189
5262
|
"Content-Type": "application/json",
|
|
@@ -5201,10 +5274,10 @@ async function callAnthropic(systemPrompt, userMessage) {
|
|
|
5201
5274
|
})
|
|
5202
5275
|
});
|
|
5203
5276
|
if (!response.ok) {
|
|
5204
|
-
const error = await readResponseText(response,
|
|
5277
|
+
const error = await readResponseText(response, signal, 64 * 1024).catch(() => "unknown error");
|
|
5205
5278
|
throw new Error(`Anthropic API error (${response.status}): ${error}`);
|
|
5206
5279
|
}
|
|
5207
|
-
const data = await readResponseJson(response);
|
|
5280
|
+
const data = await readResponseJson(response, signal);
|
|
5208
5281
|
return {
|
|
5209
5282
|
content: data.content[0]?.text ?? "",
|
|
5210
5283
|
usage: data.usage ? {
|
|
@@ -5709,6 +5782,57 @@ function withTimeout(promise, ms, label) {
|
|
|
5709
5782
|
);
|
|
5710
5783
|
});
|
|
5711
5784
|
}
|
|
5785
|
+
function withTimeoutSignal(operation, ms, label, parentSignal) {
|
|
5786
|
+
const controller = new AbortController();
|
|
5787
|
+
const signal = parentSignal ? AbortSignal.any([parentSignal, controller.signal]) : controller.signal;
|
|
5788
|
+
return new Promise((resolve2, reject) => {
|
|
5789
|
+
let settled = false;
|
|
5790
|
+
let timedOut = false;
|
|
5791
|
+
let timer;
|
|
5792
|
+
const cleanup = () => {
|
|
5793
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
5794
|
+
parentSignal?.removeEventListener("abort", onParentAbort);
|
|
5795
|
+
};
|
|
5796
|
+
const onParentAbort = () => {
|
|
5797
|
+
if (settled || timedOut) return;
|
|
5798
|
+
settled = true;
|
|
5799
|
+
cleanup();
|
|
5800
|
+
reject(parentSignal?.reason ?? new Error(`${label} aborted`));
|
|
5801
|
+
};
|
|
5802
|
+
parentSignal?.addEventListener("abort", onParentAbort, { once: true });
|
|
5803
|
+
timer = setTimeout(() => {
|
|
5804
|
+
if (settled) return;
|
|
5805
|
+
timedOut = true;
|
|
5806
|
+
controller.abort(new Error(`${label} timed out after ${ms}ms`));
|
|
5807
|
+
settled = true;
|
|
5808
|
+
cleanup();
|
|
5809
|
+
reject(new Error(`${label} timed out after ${ms}ms`));
|
|
5810
|
+
}, ms);
|
|
5811
|
+
let pending;
|
|
5812
|
+
try {
|
|
5813
|
+
pending = operation(signal);
|
|
5814
|
+
} catch (error) {
|
|
5815
|
+
settled = true;
|
|
5816
|
+
cleanup();
|
|
5817
|
+
reject(error);
|
|
5818
|
+
return;
|
|
5819
|
+
}
|
|
5820
|
+
pending.then(
|
|
5821
|
+
(value) => {
|
|
5822
|
+
if (settled) return;
|
|
5823
|
+
settled = true;
|
|
5824
|
+
cleanup();
|
|
5825
|
+
resolve2(value);
|
|
5826
|
+
},
|
|
5827
|
+
(error) => {
|
|
5828
|
+
if (settled) return;
|
|
5829
|
+
settled = true;
|
|
5830
|
+
cleanup();
|
|
5831
|
+
reject(timedOut ? new Error(`${label} timed out after ${ms}ms`) : error);
|
|
5832
|
+
}
|
|
5833
|
+
);
|
|
5834
|
+
});
|
|
5835
|
+
}
|
|
5712
5836
|
var init_timeout = __esm({
|
|
5713
5837
|
"src/timeout.ts"() {
|
|
5714
5838
|
"use strict";
|
|
@@ -6573,16 +6697,18 @@ async function searchObservations(options) {
|
|
|
6573
6697
|
);
|
|
6574
6698
|
} else {
|
|
6575
6699
|
const EMBEDDING_TIMEOUT_MS = 15e3;
|
|
6576
|
-
queryVector = await
|
|
6577
|
-
provider2.embedInput ? provider2.embedInput(
|
|
6700
|
+
queryVector = await withTimeoutSignal(
|
|
6701
|
+
(signal) => provider2.embedInput ? provider2.embedInput(
|
|
6578
6702
|
{ modality: "text", text: expandedEmbeddingQuery },
|
|
6579
|
-
{ intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false }
|
|
6703
|
+
{ intent: "query", timeoutMs: EMBEDDING_TIMEOUT_MS, retry: false, signal }
|
|
6580
6704
|
) : provider2.embed(expandedEmbeddingQuery, {
|
|
6581
6705
|
timeoutMs: EMBEDDING_TIMEOUT_MS,
|
|
6582
|
-
retry: false
|
|
6706
|
+
retry: false,
|
|
6707
|
+
signal
|
|
6583
6708
|
}),
|
|
6584
6709
|
EMBEDDING_TIMEOUT_MS,
|
|
6585
|
-
"Embedding"
|
|
6710
|
+
"Embedding",
|
|
6711
|
+
options.signal
|
|
6586
6712
|
);
|
|
6587
6713
|
mark("embedding");
|
|
6588
6714
|
const cjkRatio = (originalQuery.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) || []).length / originalQuery.length;
|
|
@@ -145002,7 +145128,13 @@ async function maintainLongTermMemories(input) {
|
|
|
145002
145128
|
}
|
|
145003
145129
|
for (const group of groups.values()) {
|
|
145004
145130
|
if (group.length < 2) continue;
|
|
145005
|
-
group.sort((a, b) =>
|
|
145131
|
+
group.sort((a, b) => {
|
|
145132
|
+
const byCreatedAt = Date.parse(b.createdAt) - Date.parse(a.createdAt);
|
|
145133
|
+
if (byCreatedAt !== 0) return byCreatedAt;
|
|
145134
|
+
const byUpdatedAt = Date.parse(b.updatedAt) - Date.parse(a.updatedAt);
|
|
145135
|
+
if (byUpdatedAt !== 0) return byUpdatedAt;
|
|
145136
|
+
return b.id.localeCompare(a.id);
|
|
145137
|
+
});
|
|
145006
145138
|
const newest = group[0];
|
|
145007
145139
|
for (const older of group.slice(1)) {
|
|
145008
145140
|
try {
|
|
@@ -148730,6 +148862,7 @@ var init_task_lens = __esm({
|
|
|
148730
148862
|
var workflows_exports = {};
|
|
148731
148863
|
__export(workflows_exports, {
|
|
148732
148864
|
WORKFLOW_ADAPTER_TARGETS: () => WORKFLOW_ADAPTER_TARGETS,
|
|
148865
|
+
WORKFLOW_AGENT_TARGETS: () => WORKFLOW_AGENT_TARGETS,
|
|
148733
148866
|
applyWorkflowAdapter: () => applyWorkflowAdapter,
|
|
148734
148867
|
importWindsurfWorkflows: () => importWindsurfWorkflows,
|
|
148735
148868
|
parseWorkflowMarkdown: () => parseWorkflowMarkdown,
|
|
@@ -148795,7 +148928,7 @@ function optionalStatus(data) {
|
|
|
148795
148928
|
return value;
|
|
148796
148929
|
}
|
|
148797
148930
|
function normalizeAgents(values) {
|
|
148798
|
-
const unknown3 = values.filter((value) => !
|
|
148931
|
+
const unknown3 = values.filter((value) => !WORKFLOW_AGENT_TARGETS.includes(value));
|
|
148799
148932
|
if (unknown3.length > 0) {
|
|
148800
148933
|
throw new Error("workflow frontmatter has unsupported agent: " + unknown3[0]);
|
|
148801
148934
|
}
|
|
@@ -149071,7 +149204,7 @@ function taskScore(workflow, task) {
|
|
|
149071
149204
|
return { score, reasons: [...new Set(reasons)] };
|
|
149072
149205
|
}
|
|
149073
149206
|
function selectWorkflows(input) {
|
|
149074
|
-
const selected = input.workflows.filter((workflow) => workflow.status === "active").map((workflow) => {
|
|
149207
|
+
const selected = input.workflows.filter((workflow) => workflow.status === "active" && (!input.agent || workflow.compatibleAgents.includes(input.agent))).map((workflow) => {
|
|
149075
149208
|
const match2 = taskScore(workflow, input.task);
|
|
149076
149209
|
const cautions = input.store && input.projectId ? input.store.recentFailureCautions(input.projectId, workflow.id) : [];
|
|
149077
149210
|
return {
|
|
@@ -149351,7 +149484,7 @@ async function selectWorkspaceWorkflows(input) {
|
|
|
149351
149484
|
errors: synced.errors
|
|
149352
149485
|
};
|
|
149353
149486
|
}
|
|
149354
|
-
var
|
|
149487
|
+
var WORKFLOW_AGENT_TARGETS, WORKFLOW_ADAPTER_TARGETS, STATUS_VALUES, LENS_TERMS, GENERIC_WORKFLOW_LENSES, GENERIC_WORKFLOW_TERMS;
|
|
149355
149488
|
var init_workflows2 = __esm({
|
|
149356
149489
|
"src/knowledge/workflows.ts"() {
|
|
149357
149490
|
"use strict";
|
|
@@ -149363,7 +149496,7 @@ var init_workflows2 = __esm({
|
|
|
149363
149496
|
init_workflow_store();
|
|
149364
149497
|
init_outcome_store();
|
|
149365
149498
|
init_task_lens();
|
|
149366
|
-
|
|
149499
|
+
WORKFLOW_AGENT_TARGETS = [
|
|
149367
149500
|
"windsurf",
|
|
149368
149501
|
"cursor",
|
|
149369
149502
|
"claude-code",
|
|
@@ -151488,13 +151621,13 @@ function verifyType(declaredType, narrative, title) {
|
|
|
151488
151621
|
}
|
|
151489
151622
|
return { type: declaredType, corrected: false };
|
|
151490
151623
|
}
|
|
151491
|
-
async function extractFactsWithLLM(narrative, title, existingFacts) {
|
|
151624
|
+
async function extractFactsWithLLM(narrative, title, existingFacts, signal) {
|
|
151492
151625
|
try {
|
|
151493
151626
|
const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
151494
151627
|
const input = `Title: ${title}
|
|
151495
151628
|
Content: ${narrative}${existingFacts.length > 0 ? `
|
|
151496
151629
|
Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
|
|
151497
|
-
const response = await callLLM2(LLM_EXTRACT_PROMPT, input);
|
|
151630
|
+
const response = await callLLM2(LLM_EXTRACT_PROMPT, input, signal);
|
|
151498
151631
|
const text2 = response.content.trim();
|
|
151499
151632
|
const jsonMatch = text2.match(/\{[\s\S]*\}/);
|
|
151500
151633
|
if (!jsonMatch) return [];
|
|
@@ -151503,15 +151636,16 @@ Already known facts (don't repeat): ${existingFacts.join("; ")}` : ""}`;
|
|
|
151503
151636
|
if (!Array.isArray(facts)) return [];
|
|
151504
151637
|
const existingLower = new Set(existingFacts.map((f3) => f3.toLowerCase().trim()));
|
|
151505
151638
|
return facts.filter((f3) => typeof f3 === "string" && f3.length >= 5).filter((f3) => !existingLower.has(f3.toLowerCase().trim())).slice(0, 10);
|
|
151506
|
-
} catch {
|
|
151639
|
+
} catch (error) {
|
|
151640
|
+
if (signal?.aborted) throw error;
|
|
151507
151641
|
return [];
|
|
151508
151642
|
}
|
|
151509
151643
|
}
|
|
151510
|
-
async function runExtract(input, existingEntities, useLLM = false) {
|
|
151644
|
+
async function runExtract(input, existingEntities, useLLM = false, signal) {
|
|
151511
151645
|
const callerFacts = input.facts ?? [];
|
|
151512
151646
|
let extractedFacts;
|
|
151513
151647
|
if (useLLM) {
|
|
151514
|
-
extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts);
|
|
151648
|
+
extractedFacts = await extractFactsWithLLM(input.narrative, input.title, callerFacts, signal);
|
|
151515
151649
|
if (extractedFacts.length === 0) {
|
|
151516
151650
|
extractedFacts = extractFacts2(input.narrative, callerFacts);
|
|
151517
151651
|
}
|
|
@@ -151731,7 +151865,7 @@ function mergeFacts2(oldFacts, newFacts) {
|
|
|
151731
151865
|
}
|
|
151732
151866
|
return merged;
|
|
151733
151867
|
}
|
|
151734
|
-
async function resolveWithLLM(extracted, hits, getObservation2) {
|
|
151868
|
+
async function resolveWithLLM(extracted, hits, getObservation2, signal) {
|
|
151735
151869
|
try {
|
|
151736
151870
|
const { callLLM: callLLM2 } = await Promise.resolve().then(() => (init_provider2(), provider_exports2));
|
|
151737
151871
|
const existingMemories = hits.slice(0, 5).map((h2, i2) => ({
|
|
@@ -151748,7 +151882,7 @@ Facts: ${extracted.facts.join("; ")}
|
|
|
151748
151882
|
|
|
151749
151883
|
EXISTING MEMORIES:
|
|
151750
151884
|
${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Facts: ${m2.facts}`).join("\n")}`;
|
|
151751
|
-
const response = await callLLM2(LLM_RESOLVE_PROMPT, input);
|
|
151885
|
+
const response = await callLLM2(LLM_RESOLVE_PROMPT, input, signal);
|
|
151752
151886
|
const text2 = response.content.trim();
|
|
151753
151887
|
const jsonMatch = text2.match(/\{[\s\S]*\}/);
|
|
151754
151888
|
if (!jsonMatch) return null;
|
|
@@ -151785,7 +151919,8 @@ ${existingMemories.map((m2) => `[ID:${m2.id}] ${m2.title} | ${m2.content} | Fact
|
|
|
151785
151919
|
};
|
|
151786
151920
|
}
|
|
151787
151921
|
return null;
|
|
151788
|
-
} catch {
|
|
151922
|
+
} catch (error) {
|
|
151923
|
+
if (signal?.aborted) throw error;
|
|
151789
151924
|
return null;
|
|
151790
151925
|
}
|
|
151791
151926
|
}
|
|
@@ -151803,19 +151938,20 @@ function scoreCandidate(extracted, candidate) {
|
|
|
151803
151938
|
const contradiction = hasContradiction(candidate.narrative, extracted.narrative);
|
|
151804
151939
|
return { score, searchSimilarity, entityMatch, richer, contradiction };
|
|
151805
151940
|
}
|
|
151806
|
-
async function runResolve(extracted, projectId, searchMemories, getObservation2, useLLM = false) {
|
|
151941
|
+
async function runResolve(extracted, projectId, searchMemories, getObservation2, useLLM = false, signal) {
|
|
151807
151942
|
const query = `${extracted.title} ${extracted.narrative.substring(0, 200)}`;
|
|
151808
151943
|
let hits;
|
|
151809
151944
|
try {
|
|
151810
|
-
hits = await searchMemories(query, 5, projectId);
|
|
151811
|
-
} catch {
|
|
151945
|
+
hits = await searchMemories(query, 5, projectId, signal);
|
|
151946
|
+
} catch (error) {
|
|
151947
|
+
if (signal?.aborted) throw error;
|
|
151812
151948
|
return { action: "new", reason: "Search unavailable, defaulting to new" };
|
|
151813
151949
|
}
|
|
151814
151950
|
if (hits.length === 0) {
|
|
151815
151951
|
return { action: "new", reason: "No similar existing memories found" };
|
|
151816
151952
|
}
|
|
151817
151953
|
if (useLLM) {
|
|
151818
|
-
const llmResult = await resolveWithLLM(extracted, hits, getObservation2);
|
|
151954
|
+
const llmResult = await resolveWithLLM(extracted, hits, getObservation2, signal);
|
|
151819
151955
|
if (llmResult) return llmResult;
|
|
151820
151956
|
}
|
|
151821
151957
|
const scored = hits.map((hit) => ({
|
|
@@ -152237,7 +152373,7 @@ async function runFormation(input, config) {
|
|
|
152237
152373
|
const existingEntities = config.getEntityNames();
|
|
152238
152374
|
const extractStartTime = Date.now();
|
|
152239
152375
|
emitStageEvent("extract", "start");
|
|
152240
|
-
const extraction = await runExtract(input, existingEntities, config.useLLM);
|
|
152376
|
+
const extraction = await runExtract(input, existingEntities, config.useLLM, config.signal);
|
|
152241
152377
|
stageDurationsMs.extract = Date.now() - extractStartTime;
|
|
152242
152378
|
emitStageEvent("extract", "success", stageDurationsMs.extract);
|
|
152243
152379
|
stagesCompleted = 1;
|
|
@@ -152257,7 +152393,8 @@ async function runFormation(input, config) {
|
|
|
152257
152393
|
input.projectId,
|
|
152258
152394
|
config.searchMemories,
|
|
152259
152395
|
config.getObservation,
|
|
152260
|
-
config.useLLM
|
|
152396
|
+
config.useLLM,
|
|
152397
|
+
config.signal
|
|
152261
152398
|
);
|
|
152262
152399
|
stageDurationsMs.resolve = Date.now() - resolveStartTime;
|
|
152263
152400
|
emitStageEvent("resolve", "success", stageDurationsMs.resolve);
|
|
@@ -153010,6 +153147,15 @@ function workflowOutput(selection) {
|
|
|
153010
153147
|
cautions: selection.cautions.map((caution) => short(caution, 22))
|
|
153011
153148
|
};
|
|
153012
153149
|
}
|
|
153150
|
+
function workflowLoadout(agent, selections) {
|
|
153151
|
+
if (!agent) return void 0;
|
|
153152
|
+
return {
|
|
153153
|
+
agent,
|
|
153154
|
+
workflowIds: selections.map((selection) => selection.workflow.id),
|
|
153155
|
+
requiredContext: unique(selections.flatMap((selection) => selection.workflow.requiredContext)).map((item) => short(item, 18)).slice(0, 4),
|
|
153156
|
+
allowedTools: unique(selections.flatMap((selection) => selection.workflow.allowedTools)).map((item) => short(item, 12)).slice(0, 6)
|
|
153157
|
+
};
|
|
153158
|
+
}
|
|
153013
153159
|
function appendLine(lines, candidate, maxTokens, omitted, omittedKind, selected, receiptSelection) {
|
|
153014
153160
|
const next = lines.length ? lines.join("\n") + "\n" + candidate : candidate;
|
|
153015
153161
|
if (countTextTokens(next) <= maxTokens) {
|
|
@@ -153470,6 +153616,22 @@ function renderTaskWorksetPrompt(input) {
|
|
|
153470
153616
|
);
|
|
153471
153617
|
}
|
|
153472
153618
|
}
|
|
153619
|
+
if (input.agentLoadout) {
|
|
153620
|
+
appendLine(lines, "", maxTokens, omitted, "agent-loadout-heading");
|
|
153621
|
+
appendLine(lines, "Agent loadout (" + input.agentLoadout.agent + ")", maxTokens, omitted, "agent-loadout-heading");
|
|
153622
|
+
for (const required of input.agentLoadout.requiredContext.slice(0, 2)) {
|
|
153623
|
+
appendLine(lines, "- Need: " + required, maxTokens, omitted, "agent-loadout-context");
|
|
153624
|
+
}
|
|
153625
|
+
if (input.agentLoadout.allowedTools.length > 0) {
|
|
153626
|
+
appendLine(
|
|
153627
|
+
lines,
|
|
153628
|
+
"- Workflow tools: " + input.agentLoadout.allowedTools.join(", "),
|
|
153629
|
+
maxTokens,
|
|
153630
|
+
omitted,
|
|
153631
|
+
"agent-loadout-tools"
|
|
153632
|
+
);
|
|
153633
|
+
}
|
|
153634
|
+
}
|
|
153473
153635
|
if (input.verification.length > 0) {
|
|
153474
153636
|
appendLine(lines, "", maxTokens, omitted, "verification-heading");
|
|
153475
153637
|
appendLine(lines, "Verify", maxTokens, omitted, "verification-heading");
|
|
@@ -153561,6 +153723,7 @@ async function buildTaskWorkset(input) {
|
|
|
153561
153723
|
let workspace;
|
|
153562
153724
|
let pages = [];
|
|
153563
153725
|
let workflows = [];
|
|
153726
|
+
let workflowSelections = [];
|
|
153564
153727
|
try {
|
|
153565
153728
|
workspace = await preferredWorkspace(input.projectId, input.dataDir);
|
|
153566
153729
|
if (workspace) {
|
|
@@ -153577,14 +153740,15 @@ async function buildTaskWorkset(input) {
|
|
|
153577
153740
|
if (task) {
|
|
153578
153741
|
const workflowStore = new WorkflowStore();
|
|
153579
153742
|
await workflowStore.init(input.dataDir);
|
|
153580
|
-
|
|
153743
|
+
workflowSelections = selectWorkflows({
|
|
153581
153744
|
workflows: workflowStore.listWorkflows(workspace.id, "active"),
|
|
153582
153745
|
task,
|
|
153583
153746
|
projectId: input.projectId,
|
|
153584
153747
|
store: workflowStore,
|
|
153748
|
+
...input.agent ? { agent: input.agent } : {},
|
|
153585
153749
|
limit: 2
|
|
153586
153750
|
});
|
|
153587
|
-
workflows =
|
|
153751
|
+
workflows = workflowSelections.map(workflowOutput);
|
|
153588
153752
|
for (const workflow of workflows) {
|
|
153589
153753
|
for (const caution of workflow.cautions) {
|
|
153590
153754
|
cautions.push({ kind: "workflow-failed-verification", message: caution });
|
|
@@ -153606,6 +153770,10 @@ async function buildTaskWorkset(input) {
|
|
|
153606
153770
|
workflows
|
|
153607
153771
|
});
|
|
153608
153772
|
const governedDurableIds = new Set(governed.durableMemory.map((memory) => memory.id));
|
|
153773
|
+
const agentLoadout = workflowLoadout(
|
|
153774
|
+
input.agent,
|
|
153775
|
+
workflowSelections.filter((selection2) => governed.workflows.some((workflow) => workflow.id === selection2.workflow.id))
|
|
153776
|
+
);
|
|
153609
153777
|
const evidenceIds = unique(governed.claims.flatMap((claim) => evidenceIdsForClaim(
|
|
153610
153778
|
claim,
|
|
153611
153779
|
evidenceByClaim.get(claim.id) ?? []
|
|
@@ -153650,6 +153818,7 @@ async function buildTaskWorkset(input) {
|
|
|
153650
153818
|
pages: pages.filter((page) => page.claimIds.some((claimId) => governed.claims.some((claim) => claim.id === claimId))),
|
|
153651
153819
|
durableMemory: governed.durableMemory,
|
|
153652
153820
|
workflows: governed.workflows,
|
|
153821
|
+
...agentLoadout ? { agentLoadout } : {},
|
|
153653
153822
|
cautions: normalizedCautions,
|
|
153654
153823
|
verification,
|
|
153655
153824
|
evidenceIds,
|
|
@@ -153868,10 +154037,12 @@ var init_current_facts = __esm({
|
|
|
153868
154037
|
var external_provider_exports = {};
|
|
153869
154038
|
__export(external_provider_exports, {
|
|
153870
154039
|
DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS: () => DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS,
|
|
154040
|
+
EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS: () => EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS,
|
|
153871
154041
|
MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES: () => MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES,
|
|
153872
154042
|
MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS: () => MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS,
|
|
153873
154043
|
getExternalCodeGraphContext: () => getExternalCodeGraphContext,
|
|
153874
|
-
inspectExternalCodeGraph: () => inspectExternalCodeGraph
|
|
154044
|
+
inspectExternalCodeGraph: () => inspectExternalCodeGraph,
|
|
154045
|
+
runExternalCodeGraphLifecycle: () => runExternalCodeGraphLifecycle
|
|
153875
154046
|
});
|
|
153876
154047
|
import { spawn as spawn5 } from "child_process";
|
|
153877
154048
|
import { existsSync as existsSync15, readFileSync as readFileSync10 } from "fs";
|
|
@@ -154070,6 +154241,66 @@ async function inspectExternalCodeGraph(input) {
|
|
|
154070
154241
|
const health = healthFromStatus(status);
|
|
154071
154242
|
return { health, quality: providerQuality({ mode, health }) };
|
|
154072
154243
|
}
|
|
154244
|
+
async function runExternalCodeGraphLifecycle(input) {
|
|
154245
|
+
const mode = input.mode ?? "auto";
|
|
154246
|
+
if (mode === "off") {
|
|
154247
|
+
const health = { state: "disabled", reason: "External CodeGraph is disabled by configuration." };
|
|
154248
|
+
return {
|
|
154249
|
+
action: input.action,
|
|
154250
|
+
performed: false,
|
|
154251
|
+
message: "External CodeGraph is disabled by configuration.",
|
|
154252
|
+
health,
|
|
154253
|
+
quality: providerQuality({ mode, health })
|
|
154254
|
+
};
|
|
154255
|
+
}
|
|
154256
|
+
const indexPath = join20(input.projectRoot, ".codegraph");
|
|
154257
|
+
if (input.action === "sync" && !existsSync15(indexPath)) {
|
|
154258
|
+
const health = { state: "not-detected", reason: "No local .codegraph index is present for this project." };
|
|
154259
|
+
return {
|
|
154260
|
+
action: input.action,
|
|
154261
|
+
performed: false,
|
|
154262
|
+
message: 'Initialize CodeGraph first with "memorix codegraph init".',
|
|
154263
|
+
health,
|
|
154264
|
+
quality: providerQuality({ mode, health })
|
|
154265
|
+
};
|
|
154266
|
+
}
|
|
154267
|
+
if (input.action === "init" && existsSync15(indexPath)) {
|
|
154268
|
+
const inspected2 = await inspectExternalCodeGraph(input);
|
|
154269
|
+
return {
|
|
154270
|
+
action: input.action,
|
|
154271
|
+
performed: false,
|
|
154272
|
+
message: "A local CodeGraph directory already exists; no initialization was performed.",
|
|
154273
|
+
...inspected2
|
|
154274
|
+
};
|
|
154275
|
+
}
|
|
154276
|
+
const result = await runSafely(input.runner ?? defaultRunner, {
|
|
154277
|
+
command: input.command,
|
|
154278
|
+
args: input.action === "init" ? ["init", input.projectRoot] : ["sync", input.projectRoot, "--quiet"],
|
|
154279
|
+
cwd: input.projectRoot,
|
|
154280
|
+
// A context read must stay fast; an explicit user-requested index sync is
|
|
154281
|
+
// a different operation and gets its own bounded maintenance window.
|
|
154282
|
+
timeoutMs: EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS,
|
|
154283
|
+
maxOutputBytes: MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES
|
|
154284
|
+
});
|
|
154285
|
+
if (!result.ok) {
|
|
154286
|
+
const health = unavailableHealth(result);
|
|
154287
|
+
return {
|
|
154288
|
+
action: input.action,
|
|
154289
|
+
performed: false,
|
|
154290
|
+
message: "CodeGraph " + input.action + " did not complete: " + (health.reason ?? "unknown local error"),
|
|
154291
|
+
health,
|
|
154292
|
+
quality: providerQuality({ mode, health })
|
|
154293
|
+
};
|
|
154294
|
+
}
|
|
154295
|
+
const inspected = await inspectExternalCodeGraph(input);
|
|
154296
|
+
const remainsStale = inspected.health.state === "stale";
|
|
154297
|
+
return {
|
|
154298
|
+
action: input.action,
|
|
154299
|
+
performed: true,
|
|
154300
|
+
message: input.action === "init" ? 'Local CodeGraph initialization completed. Run "memorix codegraph sync" when source changes.' : remainsStale ? "Local CodeGraph synchronization completed, but the graph remains stale against the current worktree; this task will use Lite evidence." : "Local CodeGraph synchronization completed and is ready for task-scoped semantic context.",
|
|
154301
|
+
...inspected
|
|
154302
|
+
};
|
|
154303
|
+
}
|
|
154073
154304
|
function safeRelativePath(projectRoot, value, exclude) {
|
|
154074
154305
|
const path34 = safeText(value, 1024);
|
|
154075
154306
|
if (!path34 || isAbsolute(path34)) return void 0;
|
|
@@ -154195,7 +154426,7 @@ async function getExternalCodeGraphContext(input) {
|
|
|
154195
154426
|
quality: providerQuality({ mode, health: inspected.health, ...contributes ? { selected: "external" } : {} })
|
|
154196
154427
|
};
|
|
154197
154428
|
}
|
|
154198
|
-
var DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES, MAX_EXTERNAL_NODE_COUNT, MAX_EXTERNAL_EDGE_COUNT, MAX_EXTERNAL_FILE_COUNT, MAX_EXTERNAL_TEXT_LENGTH, LITE_SUPPORTED_LANGUAGES, defaultRunner;
|
|
154429
|
+
var DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS, EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS, MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES, MAX_EXTERNAL_NODE_COUNT, MAX_EXTERNAL_EDGE_COUNT, MAX_EXTERNAL_FILE_COUNT, MAX_EXTERNAL_TEXT_LENGTH, LITE_SUPPORTED_LANGUAGES, defaultRunner;
|
|
154199
154430
|
var init_external_provider = __esm({
|
|
154200
154431
|
"src/codegraph/external-provider.ts"() {
|
|
154201
154432
|
"use strict";
|
|
@@ -154205,6 +154436,7 @@ var init_external_provider = __esm({
|
|
|
154205
154436
|
init_ids();
|
|
154206
154437
|
DEFAULT_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 1200;
|
|
154207
154438
|
MAX_EXTERNAL_CODEGRAPH_TIMEOUT_MS = 5e3;
|
|
154439
|
+
EXTERNAL_CODEGRAPH_LIFECYCLE_TIMEOUT_MS = 3e4;
|
|
154208
154440
|
MAX_EXTERNAL_CODEGRAPH_OUTPUT_BYTES = 256 * 1024;
|
|
154209
154441
|
MAX_EXTERNAL_NODE_COUNT = 16;
|
|
154210
154442
|
MAX_EXTERNAL_EDGE_COUNT = 24;
|
|
@@ -155030,6 +155262,7 @@ async function buildAutoProjectContext(input) {
|
|
|
155030
155262
|
projectId: input.project.id,
|
|
155031
155263
|
dataDir: input.dataDir,
|
|
155032
155264
|
...task ? { task } : {},
|
|
155265
|
+
...input.agent ? { agent: input.agent } : {},
|
|
155033
155266
|
lens: lens.id,
|
|
155034
155267
|
startHere,
|
|
155035
155268
|
...alwaysOn.profile.length > 0 || alwaysOn.state || alwaysOn.durable.length > 0 ? { alwaysOn } : {},
|
|
@@ -155366,6 +155599,34 @@ var init_auto_context = __esm({
|
|
|
155366
155599
|
}
|
|
155367
155600
|
});
|
|
155368
155601
|
|
|
155602
|
+
// src/knowledge/context-receipt.ts
|
|
155603
|
+
var context_receipt_exports = {};
|
|
155604
|
+
__export(context_receipt_exports, {
|
|
155605
|
+
buildBoundedContextReceipt: () => buildBoundedContextReceipt
|
|
155606
|
+
});
|
|
155607
|
+
function buildBoundedContextReceipt(input) {
|
|
155608
|
+
const provider2 = input.providerQuality ?? input.workset.provenance.codeProvider;
|
|
155609
|
+
return {
|
|
155610
|
+
schemaVersion: "1",
|
|
155611
|
+
task: input.workset.task,
|
|
155612
|
+
brief: input.workset.prompt,
|
|
155613
|
+
receipt: input.workset.receipt,
|
|
155614
|
+
code: {
|
|
155615
|
+
selected: provider2?.selected ?? "lite",
|
|
155616
|
+
quality: provider2?.selectedQuality ?? "heuristic",
|
|
155617
|
+
externalState: provider2?.external.state ?? "not-detected",
|
|
155618
|
+
...input.workset.provenance.snapshotId ? { snapshotId: input.workset.provenance.snapshotId } : {}
|
|
155619
|
+
},
|
|
155620
|
+
...input.workset.agentLoadout ? { loadout: input.workset.agentLoadout } : {}
|
|
155621
|
+
};
|
|
155622
|
+
}
|
|
155623
|
+
var init_context_receipt = __esm({
|
|
155624
|
+
"src/knowledge/context-receipt.ts"() {
|
|
155625
|
+
"use strict";
|
|
155626
|
+
init_esm_shims();
|
|
155627
|
+
}
|
|
155628
|
+
});
|
|
155629
|
+
|
|
155369
155630
|
// src/codegraph/context-pack.ts
|
|
155370
155631
|
var context_pack_exports = {};
|
|
155371
155632
|
__export(context_pack_exports, {
|
|
@@ -155524,6 +155785,7 @@ async function attachTaskWorkset(input) {
|
|
|
155524
155785
|
projectId: input.projectId,
|
|
155525
155786
|
dataDir: input.dataDir,
|
|
155526
155787
|
task: input.pack.task,
|
|
155788
|
+
...input.agent ? { agent: input.agent } : {},
|
|
155527
155789
|
lens: input.lens,
|
|
155528
155790
|
currentFacts: input.currentFacts ?? [],
|
|
155529
155791
|
...input.codeState ? { codeState: input.codeState } : {},
|
|
@@ -159916,8 +160178,8 @@ var init_official_skills = __esm({
|
|
|
159916
160178
|
"",
|
|
159917
160179
|
"| Situation | Prefer | CLI fallback |",
|
|
159918
160180
|
"|---|---|---|",
|
|
159919
|
-
'| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --json` |',
|
|
159920
|
-
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --json` |',
|
|
160181
|
+
'| Starting a coding task and needing the best task-lensed project map | `memorix_project_context` with the user\'s task | `memorix context "<task>" --brief-json` |',
|
|
160182
|
+
'| Continuing prior project work | `memorix_project_context` with the user\'s task | `memorix resume "<task>" --brief-json` |',
|
|
159921
160183
|
'| Need structured refs/freshness for code-bound memories | `memorix_context_pack` | `memorix codegraph context-pack --task "<topic>"` |',
|
|
159922
160184
|
'| Explicit memory graph question | `memorix_graph_context` | `memorix memory graph-context --query "<topic>"` |',
|
|
159923
160185
|
'| Specific past decision, bug, file, or change | `memorix_search` | `memorix memory search --query "<topic>"` |',
|
|
@@ -159930,7 +160192,7 @@ var init_official_skills = __esm({
|
|
|
159930
160192
|
"",
|
|
159931
160193
|
"- Default first step for non-trivial coding work: call `memorix_project_context` before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Pass the user's actual task so Memorix can choose a bugfix, feature, release, onboarding, refactor, docs, test, or general brief. Start by reading its suggested files.",
|
|
159932
160194
|
"- In Claude Code headless/print-mode, an initial MCP `pending` status is not a failure by itself. Prefer MCP first: use the client's tool discovery/dynamic loading to find `memorix_project_context` when it is not in the first visible tool list.",
|
|
159933
|
-
'- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --json` instead. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
|
|
160195
|
+
'- Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run `memorix resume "<task>" --brief-json` exactly once before inspecting files, Git history, progress notes, or guessing. The absence of `.memorix` or visible memory files never proves project memory is empty. For a new task, use `memorix context "<task>" --brief-json` instead. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally; do not probe help, enumerate commands, or chain broad searches.',
|
|
159934
160196
|
"- After a successful `memorix_project_context`, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use Context Pack, search, or detail only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
|
|
159935
160197
|
"- If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
|
|
159936
160198
|
"- Use `memorix_search` for a specific decision, bug, file, or prior change that the project context did not answer. Fetch detail only for a result you still need after the brief.",
|
|
@@ -161189,7 +161451,7 @@ alwaysApply: true
|
|
|
161189
161451
|
"",
|
|
161190
161452
|
`Default first step for non-trivial coding work: call \`memorix_project_context\` with the user's actual task before progress files, dev-log reads, ad-hoc file reads, or git archaeology. Memorix will choose a task-lensed brief (bugfix, feature, release, onboarding, refactor, docs, test, or general). When the task is continuing prior work, the same brief also includes a bounded prior-work projection. Treat its "Start here" files as the first ${contextNoun} files to inspect.`,
|
|
161191
161453
|
"",
|
|
161192
|
-
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --json`. For a new task, use `memorix context "<task>" --json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
|
|
161454
|
+
'If the MCP tool is not visible yet but the client supports tool discovery or dynamic loading, search/select `memorix_project_context` first. Continuation fallback is mandatory: when the user asks to continue, resume, take over, or explain prior work and MCP cannot be called in this turn, run exactly one CLI brief with the user\'s real task before inspecting files, Git history, progress notes, or guessing: `memorix resume "<task>" --brief-json`. For a new task, use `memorix context "<task>" --brief-json` instead. The absence of `.memorix` or visible memory files never proves project memory is empty. Use `--json` only when a diagnostic needs the detailed legacy payload. If that one command fails, report it and proceed normally. Do not probe help, enumerate commands, chain broad searches, wait indefinitely on MCP startup, or hand-write tool-call syntax.',
|
|
161193
161455
|
"",
|
|
161194
161456
|
"After a successful `memorix_project_context` result, the brief is the default retrieval boundary. Do not call more Memorix retrieval tools after a complete brief. Use `memorix_context_pack`, `memorix_search`, or `memorix_detail` only when the brief lacks a specific reference, freshness field, or fact needed for the task, or when the user explicitly asks for deeper history. In MCP, name that missing fact in `purpose` when intentionally expanding beyond the brief. Do not retrieve the same decision twice just to confirm an already-complete brief.",
|
|
161195
161457
|
"If the user asks for read-only work or says not to modify files, do not call `memorix_store` just to record an assessment. Store only when the user explicitly asks to preserve it.",
|
|
@@ -165642,7 +165904,7 @@ The path should point to a directory containing a .git folder.`
|
|
|
165642
165904
|
};
|
|
165643
165905
|
const server = existingServer ?? new McpServer({
|
|
165644
165906
|
name: "memorix",
|
|
165645
|
-
version: true ? "1.
|
|
165907
|
+
version: true ? "1.6.0" : "1.0.1"
|
|
165646
165908
|
});
|
|
165647
165909
|
const originalRegisterTool = server.registerTool.bind(server);
|
|
165648
165910
|
server.registerTool = ((name, ...args) => {
|
|
@@ -165831,8 +166093,8 @@ The path should point to a directory containing a .git folder.`
|
|
|
165831
166093
|
mode: "active",
|
|
165832
166094
|
useLLM: isLLMEnabled(),
|
|
165833
166095
|
minValueScore: 0.3,
|
|
165834
|
-
searchMemories: async (q, limit2, pid) => {
|
|
165835
|
-
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader });
|
|
166096
|
+
searchMemories: async (q, limit2, pid, signal) => {
|
|
166097
|
+
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader, signal });
|
|
165836
166098
|
if (result.entries.length === 0) return [];
|
|
165837
166099
|
const details = await compactDetail(result.entries.map((e2) => e2.id), { reader });
|
|
165838
166100
|
return details.documents.map((d, i2) => ({
|
|
@@ -165862,16 +166124,19 @@ The path should point to a directory containing a .git folder.`
|
|
|
165862
166124
|
getEntityNames: () => graphManager.getEntityNames(),
|
|
165863
166125
|
onStageEvent: onFormationStageEvent
|
|
165864
166126
|
};
|
|
165865
|
-
formationResult = await
|
|
165866
|
-
|
|
165867
|
-
|
|
165868
|
-
|
|
165869
|
-
|
|
165870
|
-
|
|
165871
|
-
|
|
165872
|
-
|
|
165873
|
-
|
|
165874
|
-
|
|
166127
|
+
formationResult = await withTimeoutSignal(
|
|
166128
|
+
async (signal) => {
|
|
166129
|
+
formationConfig.signal = signal;
|
|
166130
|
+
return runFormation({
|
|
166131
|
+
entityName,
|
|
166132
|
+
type,
|
|
166133
|
+
title,
|
|
166134
|
+
narrative,
|
|
166135
|
+
facts: safeFacts,
|
|
166136
|
+
projectId: project.id,
|
|
166137
|
+
source: "explicit"
|
|
166138
|
+
}, formationConfig);
|
|
166139
|
+
},
|
|
165875
166140
|
FORMATION_TIMEOUT_MS,
|
|
165876
166141
|
"Formation pipeline"
|
|
165877
166142
|
);
|
|
@@ -166221,8 +166486,8 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
166221
166486
|
mode: formationMode,
|
|
166222
166487
|
useLLM: isLLMEnabled(),
|
|
166223
166488
|
minValueScore: 0.3,
|
|
166224
|
-
searchMemories: async (q, limit2, pid) => {
|
|
166225
|
-
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader });
|
|
166489
|
+
searchMemories: async (q, limit2, pid, signal) => {
|
|
166490
|
+
const result = await compactSearch({ query: q, limit: limit2, projectId: pid, status: "active", reader, signal });
|
|
166226
166491
|
if (result.entries.length === 0) return [];
|
|
166227
166492
|
const details = await compactDetail(result.entries.map((e2) => e2.id), { reader });
|
|
166228
166493
|
return details.documents.map((d, i2) => ({
|
|
@@ -166243,8 +166508,11 @@ Auto-enriched: ${enrichmentParts.join(", ")}` : "";
|
|
|
166243
166508
|
},
|
|
166244
166509
|
getEntityNames: () => graphManager.getEntityNames()
|
|
166245
166510
|
};
|
|
166246
|
-
const formed = await
|
|
166247
|
-
|
|
166511
|
+
const formed = await withTimeoutSignal(
|
|
166512
|
+
async (signal) => {
|
|
166513
|
+
formationConfig.signal = signal;
|
|
166514
|
+
return runFormation({ entityName, type, title, narrative, facts: safeFacts, projectId: project.id, source: "explicit", topicKey }, formationConfig);
|
|
166515
|
+
},
|
|
166248
166516
|
FORMATION_TIMEOUT_MS,
|
|
166249
166517
|
"Shadow formation"
|
|
166250
166518
|
);
|
|
@@ -166470,13 +166738,28 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
166470
166738
|
refresh: z626.enum(["auto", "always", "never"]).optional().default("auto").describe(
|
|
166471
166739
|
"Code Memory refresh policy. auto refreshes only when missing or stale."
|
|
166472
166740
|
),
|
|
166473
|
-
format: z626.enum(["prompt", "summary", "json"]).optional().default("prompt").describe(
|
|
166474
|
-
'Output format. "prompt" is agent-ready; "summary" is human-readable; "json" is
|
|
166741
|
+
format: z626.enum(["prompt", "summary", "json", "receipt"]).optional().default("prompt").describe(
|
|
166742
|
+
'Output format. "prompt" is agent-ready; "summary" is human-readable; "receipt" is bounded JSON; "json" is detailed diagnostics.'
|
|
166475
166743
|
),
|
|
166744
|
+
agent: z626.enum([
|
|
166745
|
+
"windsurf",
|
|
166746
|
+
"cursor",
|
|
166747
|
+
"claude-code",
|
|
166748
|
+
"codex",
|
|
166749
|
+
"copilot",
|
|
166750
|
+
"antigravity",
|
|
166751
|
+
"gemini-cli",
|
|
166752
|
+
"openclaw",
|
|
166753
|
+
"hermes",
|
|
166754
|
+
"omp",
|
|
166755
|
+
"kiro",
|
|
166756
|
+
"opencode",
|
|
166757
|
+
"trae"
|
|
166758
|
+
]).optional().describe("Optional target agent for compatible workflow selection."),
|
|
166476
166759
|
limit: z626.number().optional().describe("Reserved for future source limits; current prompt stays compact by default.")
|
|
166477
166760
|
}
|
|
166478
166761
|
},
|
|
166479
|
-
async ({ task, refresh, format }) => {
|
|
166762
|
+
async ({ task, refresh, format, agent }) => {
|
|
166480
166763
|
const unresolved = requireResolvedProject("build project context for the current project");
|
|
166481
166764
|
if (unresolved) return unresolved;
|
|
166482
166765
|
const [
|
|
@@ -166488,12 +166771,14 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
166488
166771
|
},
|
|
166489
166772
|
{ getObservationStore: getObservationStore2 },
|
|
166490
166773
|
{ MaintenanceJobStore: MaintenanceJobStore2 },
|
|
166491
|
-
{ enqueueCodegraphRefresh: enqueueCodegraphRefresh2 }
|
|
166774
|
+
{ enqueueCodegraphRefresh: enqueueCodegraphRefresh2 },
|
|
166775
|
+
{ buildBoundedContextReceipt: buildBoundedContextReceipt2 }
|
|
166492
166776
|
] = await Promise.all([
|
|
166493
166777
|
Promise.resolve().then(() => (init_auto_context(), auto_context_exports)),
|
|
166494
166778
|
Promise.resolve().then(() => (init_obs_store(), obs_store_exports)),
|
|
166495
166779
|
Promise.resolve().then(() => (init_maintenance_jobs(), maintenance_jobs_exports)),
|
|
166496
|
-
Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports))
|
|
166780
|
+
Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports)),
|
|
166781
|
+
Promise.resolve().then(() => (init_context_receipt(), context_receipt_exports))
|
|
166497
166782
|
]);
|
|
166498
166783
|
const observations2 = filterReadableObservations(
|
|
166499
166784
|
await getObservationStore2().loadByProject(project.id, { status: "active" }),
|
|
@@ -166504,6 +166789,7 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
166504
166789
|
dataDir: projectDir2,
|
|
166505
166790
|
observations: observations2,
|
|
166506
166791
|
task,
|
|
166792
|
+
agent,
|
|
166507
166793
|
refresh: refresh ?? "auto",
|
|
166508
166794
|
reader: getObservationReader(),
|
|
166509
166795
|
enqueueRefresh: () => {
|
|
@@ -166516,7 +166802,10 @@ _Search mode: ${getLastSearchMode2(project.id)}_`;
|
|
|
166516
166802
|
});
|
|
166517
166803
|
}
|
|
166518
166804
|
});
|
|
166519
|
-
const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "
|
|
166805
|
+
const text2 = format === "json" ? JSON.stringify({ ...context, brief: buildAutoProjectBrief2(context) }, null, 2) : format === "receipt" ? JSON.stringify(buildBoundedContextReceipt2({
|
|
166806
|
+
workset: context.workset,
|
|
166807
|
+
providerQuality: context.providerQuality
|
|
166808
|
+
}), null, 2) : format === "summary" ? formatAutoProjectContextSummary2(context) : formatAutoProjectContextPrompt2(context);
|
|
166520
166809
|
autopilotRetrievalBoundary = {
|
|
166521
166810
|
projectId: project.id,
|
|
166522
166811
|
issuedAt: Date.now(),
|