@remnic/core 9.25.5 → 9.25.7
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/dist/access-admin-ops-surface.d.ts +2 -2
- package/dist/access-authorization-probe.d.ts +2 -2
- package/dist/access-boundary.d.ts +2 -2
- package/dist/access-cli.js +1 -1
- package/dist/access-http.d.ts +2 -2
- package/dist/access-identity-continuity-surface.d.ts +1 -1
- package/dist/access-lcm-surface.d.ts +2 -2
- package/dist/access-mcp.d.ts +2 -2
- package/dist/access-observe-write-surface.d.ts +2 -2
- package/dist/access-operations.d.ts +5 -5
- package/dist/access-recall-concurrency.d.ts +2 -2
- package/dist/access-recall-response.d.ts +2 -2
- package/dist/access-recall-surface.d.ts +2 -2
- package/dist/access-schema.d.ts +76 -76
- package/dist/{access-service-BJQ22URi.d.ts → access-service-CIdWkP6J.d.ts} +1 -1
- package/dist/access-service.d.ts +2 -2
- package/dist/access-surface-catalog.d.ts +2 -2
- package/dist/bootstrap.d.ts +1 -1
- package/dist/{chunk-FR75B4UU.js → chunk-KZVPTJNZ.js} +334 -647
- package/dist/chunk-KZVPTJNZ.js.map +1 -0
- package/dist/{cli-1W7cNjJJ.d.ts → cli-Da5kesWC.d.ts} +2 -2
- package/dist/cli.d.ts +3 -3
- package/dist/explicit-capture.d.ts +1 -1
- package/dist/index.d.ts +392 -392
- package/dist/index.js +1 -1
- package/dist/mcp-memory-inspector-app.d.ts +2 -2
- package/dist/{orchestrator-BtA1wC5K.d.ts → orchestrator-CFJ_TG6D.d.ts} +15 -10
- package/dist/orchestrator.d.ts +1 -1
- package/dist/orchestrator.js +1 -1
- package/dist/schemas.d.ts +76 -76
- package/dist/shared-context/manager.d.ts +8 -8
- package/dist/transfer/types.d.ts +66 -66
- package/package.json +2 -2
- package/src/meetings/recall-exclusion.test.ts +4 -2
- package/src/orchestration/generic-recall-paths.ts +119 -0
- package/src/orchestration/namespace-read-fanout.ts +0 -12
- package/src/orchestration/orchestrator-helpers.ts +0 -35
- package/src/orchestration/recall-internal.ts +6 -6
- package/src/orchestration/recall-search-pipeline.test.ts +194 -28
- package/src/orchestration/recall-search-pipeline.ts +39 -89
- package/src/orchestrator.ts +5 -17
- package/src/recall-cold-deadline.test.ts +11 -13
- package/src/testing/subjects/generic-recall-paths.test.ts +157 -0
- package/dist/chunk-FR75B4UU.js.map +0 -1
- package/src/recall/archive-scoring.ts +0 -544
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Pins the task-level cancellation contract of runColdStepWithinDeadline
|
|
5
5
|
* inside RecallSearchPipelineCoordinator.applyColdFallbackPipeline:
|
|
6
6
|
* - when the per-step deadline wins, the losing cold task's INJECTED signal
|
|
7
|
-
* is aborted
|
|
7
|
+
* is aborted so an orphaned query-aware fallback stops cooperatively; the
|
|
8
8
|
* step returns its fallback (fail-open);
|
|
9
9
|
* - a task-level deadline must NOT abort the request-level signal;
|
|
10
10
|
* - a task that completes normally (no deadline) never aborts the injected
|
|
@@ -37,24 +37,22 @@ async function coldConfig() {
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
* Minimal
|
|
41
|
-
* the cold-
|
|
42
|
-
* an empty archive result returns [] before any namespace/storage-router work,
|
|
43
|
-
* keeping the stub surface tight. The cast is a deliberate test double.
|
|
40
|
+
* Minimal dependencies for the query-aware fallback. QMD is unavailable, so
|
|
41
|
+
* the cold-QMD branch is skipped and the injected fallback step is observed.
|
|
44
42
|
*/
|
|
45
43
|
function coldDeps(
|
|
46
44
|
config: PluginConfig,
|
|
47
|
-
|
|
45
|
+
searchQueryAwareFallback: RecallSearchPipelineDeps["searchQueryAwareFallback"],
|
|
48
46
|
): RecallSearchPipelineDeps {
|
|
49
47
|
return {
|
|
50
48
|
config,
|
|
51
49
|
qmd: { isAvailable: () => false },
|
|
52
50
|
namespaceFromPath: () => "default",
|
|
53
|
-
|
|
51
|
+
searchQueryAwareFallback,
|
|
54
52
|
} as unknown as RecallSearchPipelineDeps;
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
test("#1907:
|
|
55
|
+
test("#1907: query-aware fallback deadline aborts the injected step signal, returns fallback, leaves the request signal intact", async () => {
|
|
58
56
|
const { memoryDir, config } = await coldConfig();
|
|
59
57
|
try {
|
|
60
58
|
const stuck = Promise.withResolvers<QmdSearchResult[]>();
|
|
@@ -65,7 +63,7 @@ test("#1907: cold archive-scan deadline aborts the injected step signal, returns
|
|
|
65
63
|
// so the late completion leaks "late" here and the assertion below fails.
|
|
66
64
|
const lateWrites: string[] = [];
|
|
67
65
|
const abandonedTaskSettled = Promise.withResolvers<void>();
|
|
68
|
-
const deps = coldDeps(config, async (_prompt,
|
|
66
|
+
const deps = coldDeps(config, async (_prompt, _limit, _prefilter, abortSignal) => {
|
|
69
67
|
capturedStepSignal = abortSignal;
|
|
70
68
|
const late = await stuck.promise; // does not settle before the deadline wins
|
|
71
69
|
if (!abortSignal?.aborted) {
|
|
@@ -87,7 +85,7 @@ test("#1907: cold archive-scan deadline aborts the injected step signal, returns
|
|
|
87
85
|
});
|
|
88
86
|
|
|
89
87
|
assert.deepEqual(result, [], "the step returns its fallback when the deadline wins");
|
|
90
|
-
assert.ok(capturedStepSignal, "
|
|
88
|
+
assert.ok(capturedStepSignal, "query-aware fallback received an injected step signal");
|
|
91
89
|
assert.equal(
|
|
92
90
|
capturedStepSignal!.aborted,
|
|
93
91
|
true,
|
|
@@ -119,7 +117,7 @@ test("#1907: a cold step that completes before its deadline never aborts the inj
|
|
|
119
117
|
const { memoryDir, config } = await coldConfig();
|
|
120
118
|
try {
|
|
121
119
|
let capturedStepSignal: AbortSignal | undefined;
|
|
122
|
-
const deps = coldDeps(config, async (_prompt,
|
|
120
|
+
const deps = coldDeps(config, async (_prompt, _limit, _prefilter, abortSignal) => {
|
|
123
121
|
capturedStepSignal = abortSignal;
|
|
124
122
|
return []; // resolves immediately, well within the deadline
|
|
125
123
|
});
|
|
@@ -135,8 +133,8 @@ test("#1907: a cold step that completes before its deadline never aborts the inj
|
|
|
135
133
|
abortSignal: requestController.signal,
|
|
136
134
|
});
|
|
137
135
|
|
|
138
|
-
assert.deepEqual(result, [], "empty
|
|
139
|
-
assert.ok(capturedStepSignal, "
|
|
136
|
+
assert.deepEqual(result, [], "empty query-aware fallback returns []");
|
|
137
|
+
assert.ok(capturedStepSignal, "query-aware fallback received an injected step signal");
|
|
140
138
|
assert.equal(
|
|
141
139
|
capturedStepSignal!.aborted,
|
|
142
140
|
false,
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
|
|
3
|
+
import { Orchestrator } from "../../orchestrator.js";
|
|
4
|
+
import type { SearchBackend } from "../../search/port.js";
|
|
5
|
+
import type { MemoryFile, PluginConfig, QmdSearchResult } from "../../types.js";
|
|
6
|
+
import {
|
|
7
|
+
cleanupDir,
|
|
8
|
+
makeLifecycleConfig,
|
|
9
|
+
mkTempMemoryDir,
|
|
10
|
+
singleFactResult,
|
|
11
|
+
stubExtraction,
|
|
12
|
+
} from "../orchestrator-lite.js";
|
|
13
|
+
import {
|
|
14
|
+
type LifecycleSubject,
|
|
15
|
+
type MatrixRow,
|
|
16
|
+
runLifecycleMatrix,
|
|
17
|
+
} from "../lifecycle-matrix.js";
|
|
18
|
+
|
|
19
|
+
interface QmdSeam {
|
|
20
|
+
qmd: SearchBackend;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface GenericRecallPathState {
|
|
24
|
+
readonly memoryDir: string;
|
|
25
|
+
orchestrator: Orchestrator;
|
|
26
|
+
readonly config: PluginConfig;
|
|
27
|
+
readonly archivePath: string;
|
|
28
|
+
readonly activePath: string;
|
|
29
|
+
readonly candidates: QmdSearchResult[];
|
|
30
|
+
recalled?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function installQmd(orchestrator: Orchestrator, candidates: QmdSearchResult[]): void {
|
|
34
|
+
const seam = orchestrator as unknown as QmdSeam;
|
|
35
|
+
seam.qmd = {
|
|
36
|
+
isAvailable: () => true,
|
|
37
|
+
debugStatus: () => "lifecycle-test-qmd",
|
|
38
|
+
search: async () => candidates,
|
|
39
|
+
hybridSearch: async () => candidates,
|
|
40
|
+
} as unknown as SearchBackend;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function result(memory: MemoryFile, score: number): QmdSearchResult {
|
|
44
|
+
return {
|
|
45
|
+
docid: memory.frontmatter.id,
|
|
46
|
+
path: memory.path,
|
|
47
|
+
score,
|
|
48
|
+
snippet: memory.content,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const subject: LifecycleSubject<GenericRecallPathState> = {
|
|
53
|
+
async setup(row: MatrixRow): Promise<GenericRecallPathState> {
|
|
54
|
+
const memoryDir = await mkTempMemoryDir(`generic-recall-${row.id}`);
|
|
55
|
+
let orchestrator: Orchestrator | undefined;
|
|
56
|
+
try {
|
|
57
|
+
const config = makeLifecycleConfig(memoryDir, {
|
|
58
|
+
qmdEnabled: true,
|
|
59
|
+
qmdSearchStrategy: "lex",
|
|
60
|
+
});
|
|
61
|
+
orchestrator = new Orchestrator(config);
|
|
62
|
+
stubExtraction(orchestrator, () => singleFactResult(`replay-${row.id}`));
|
|
63
|
+
const storage = await orchestrator.getStorage();
|
|
64
|
+
const archivedWrite = await storage.writeMemory(
|
|
65
|
+
"fact",
|
|
66
|
+
`archived candidate for ${row.id}`,
|
|
67
|
+
);
|
|
68
|
+
const archivedMemory = await storage.getMemoryById(archivedWrite.id);
|
|
69
|
+
assert.ok(archivedMemory);
|
|
70
|
+
const archivePath = await storage.archiveMemory(archivedMemory);
|
|
71
|
+
assert.ok(archivePath);
|
|
72
|
+
|
|
73
|
+
const activeWrite = await storage.writeMemory(
|
|
74
|
+
"fact",
|
|
75
|
+
`active candidate for ${row.id}`,
|
|
76
|
+
);
|
|
77
|
+
const activeMemory = await storage.getMemoryById(activeWrite.id);
|
|
78
|
+
assert.ok(activeMemory);
|
|
79
|
+
const candidates = [
|
|
80
|
+
result({ ...archivedMemory, path: archivePath }, 1),
|
|
81
|
+
result(activeMemory, 0.9),
|
|
82
|
+
];
|
|
83
|
+
installQmd(orchestrator, candidates);
|
|
84
|
+
return {
|
|
85
|
+
memoryDir,
|
|
86
|
+
orchestrator,
|
|
87
|
+
config,
|
|
88
|
+
archivePath,
|
|
89
|
+
activePath: activeMemory.path,
|
|
90
|
+
candidates,
|
|
91
|
+
};
|
|
92
|
+
} catch (error) {
|
|
93
|
+
await orchestrator?.destroy().catch(() => undefined);
|
|
94
|
+
await cleanupDir(memoryDir);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
async exercise(state, row): Promise<void> {
|
|
100
|
+
const sessionKey = `generic-recall-${row.id}`;
|
|
101
|
+
if (row.dimensions.flush !== "none") {
|
|
102
|
+
await state.orchestrator.flushSession(sessionKey, {
|
|
103
|
+
reason: row.dimensions.flush,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (row.dimensions.restart) {
|
|
107
|
+
await state.orchestrator.destroy();
|
|
108
|
+
state.orchestrator = new Orchestrator(state.config);
|
|
109
|
+
installQmd(state.orchestrator, state.candidates);
|
|
110
|
+
}
|
|
111
|
+
if (
|
|
112
|
+
row.dimensions.providerIdentity === "explicit" ||
|
|
113
|
+
(row.dimensions.providerIdentity === "sparse" && row.dimensions.rememberedBinding)
|
|
114
|
+
) {
|
|
115
|
+
state.orchestrator.setPeerIdForSession(sessionKey, "remembered-provider");
|
|
116
|
+
} else if (row.dimensions.providerIdentity === "rebound") {
|
|
117
|
+
state.orchestrator.setPeerIdForSession(sessionKey, "provider-a");
|
|
118
|
+
state.orchestrator.setPeerIdForSession(sessionKey, "provider-b");
|
|
119
|
+
}
|
|
120
|
+
if (row.dimensions.dedupeOrReplay) {
|
|
121
|
+
const replayTurn = {
|
|
122
|
+
source: "openclaw" as const,
|
|
123
|
+
sessionKey,
|
|
124
|
+
role: "user" as const,
|
|
125
|
+
content: "replayed candidate",
|
|
126
|
+
timestamp: "2026-07-25T00:00:00.000Z",
|
|
127
|
+
};
|
|
128
|
+
await state.orchestrator.ingestReplayBatch(
|
|
129
|
+
[replayTurn, { ...replayTurn }],
|
|
130
|
+
{ archiveLcm: false },
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
state.recalled = await state.orchestrator.recall("candidate", sessionKey);
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
async invariants(state): Promise<void> {
|
|
137
|
+
assert.match(state.recalled ?? "", /active candidate/);
|
|
138
|
+
assert.doesNotMatch(state.recalled ?? "", /archived candidate/);
|
|
139
|
+
assert.equal(
|
|
140
|
+
state.candidates[0]?.path,
|
|
141
|
+
state.archivePath,
|
|
142
|
+
"the QMD fixture must put the archived memory ahead of the active hit",
|
|
143
|
+
);
|
|
144
|
+
assert.equal(
|
|
145
|
+
state.candidates[1]?.path,
|
|
146
|
+
state.activePath,
|
|
147
|
+
"the QMD fixture must include the persisted active memory",
|
|
148
|
+
);
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
async teardown(state): Promise<void> {
|
|
152
|
+
await state.orchestrator.destroy();
|
|
153
|
+
await cleanupDir(state.memoryDir);
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
runLifecycleMatrix("generic-recall-paths", subject);
|