@remnic/bench 9.6.9 → 9.6.11
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/index.d.ts +11 -0
- package/dist/index.js +266 -8
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -131,6 +131,17 @@ interface BenchMemoryAdapter {
|
|
|
131
131
|
store(sessionId: string, messages: Message[], control?: BenchPhaseControl): Promise<void>;
|
|
132
132
|
recall(sessionId: string, query: string, budgetChars?: number, options?: BenchRecallOptions, control?: BenchPhaseControl): Promise<string>;
|
|
133
133
|
search(query: string, limit: number, sessionId?: string, control?: BenchPhaseControl): Promise<SearchResult[]>;
|
|
134
|
+
/**
|
|
135
|
+
* Optional explicit-correction surface (issue #1584 plan item 2a). Routes a
|
|
136
|
+
* natural-language correction through the system's correction contract
|
|
137
|
+
* (plan + confirmed apply) instead of a plain turn store. Resolves
|
|
138
|
+
* `{ applied: false }` when the planner produced no applicable actions so
|
|
139
|
+
* the caller can fall back to the turn path. Adapters without an explicit
|
|
140
|
+
* correction surface omit this method entirely.
|
|
141
|
+
*/
|
|
142
|
+
correct?(sessionId: string, text: string, at?: string, control?: BenchPhaseControl): Promise<{
|
|
143
|
+
applied: boolean;
|
|
144
|
+
}>;
|
|
134
145
|
reset(sessionId?: string, control?: BenchPhaseControl): Promise<void>;
|
|
135
146
|
getStats(sessionId?: string, control?: BenchPhaseControl): Promise<MemoryStats>;
|
|
136
147
|
/** Wait for background summarization (e.g. LCM) to finish after store(). */
|
package/dist/index.js
CHANGED
|
@@ -620,6 +620,7 @@ import {
|
|
|
620
620
|
buildExplicitCueRecallSection,
|
|
621
621
|
buildTrajectoryAnalysisRecallSection,
|
|
622
622
|
collectExplicitTurnReferences,
|
|
623
|
+
EngramAccessService,
|
|
623
624
|
expandTildePath,
|
|
624
625
|
normalizeTurnExpansionEnd,
|
|
625
626
|
Orchestrator,
|
|
@@ -1131,6 +1132,27 @@ function benchCoreMemoryTier(memory) {
|
|
|
1131
1132
|
function benchCoreMemorySource(sessionId) {
|
|
1132
1133
|
return `bench-replay-${createHash("sha256").update(sessionId).digest("hex").slice(0, 16)}`;
|
|
1133
1134
|
}
|
|
1135
|
+
function resolveSessionScopedCorrectionDecision(plan, ownedIds, phase) {
|
|
1136
|
+
const actionTargets = [];
|
|
1137
|
+
for (const action of plan.actions) {
|
|
1138
|
+
if (action.kind === "supersede") actionTargets.push(action.loserId);
|
|
1139
|
+
else if (action.kind !== "redaction_rule") actionTargets.push(action.memoryId);
|
|
1140
|
+
}
|
|
1141
|
+
const foreignIds = actionTargets.filter((id) => !ownedIds.has(id));
|
|
1142
|
+
if (phase === "initial") {
|
|
1143
|
+
const ownedAffected = plan.affected.filter((entry) => ownedIds.has(entry.memoryId));
|
|
1144
|
+
if (plan.affected.length > 0 && ownedAffected.length === 0) {
|
|
1145
|
+
return { kind: "no-owned-target" };
|
|
1146
|
+
}
|
|
1147
|
+
if (ownedAffected.length < plan.affected.length) {
|
|
1148
|
+
return { kind: "replan", targetIds: ownedAffected.map((entry) => entry.memoryId) };
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
if (foreignIds.length > 0) {
|
|
1152
|
+
return { kind: "foreign-actions", foreignIds };
|
|
1153
|
+
}
|
|
1154
|
+
return { kind: "proceed" };
|
|
1155
|
+
}
|
|
1134
1156
|
function benchEntityStructuredFactSourceDir(memoryDir) {
|
|
1135
1157
|
return path.join(memoryDir, "state", "bench-entity-structured-facts");
|
|
1136
1158
|
}
|
|
@@ -1837,6 +1859,16 @@ function createAdapterFactory(mode) {
|
|
|
1837
1859
|
coreReplayChain = coreReplayChain.catch(() => void 0).then(() => trackedCleanup).catch(() => void 0);
|
|
1838
1860
|
void trackedCleanup;
|
|
1839
1861
|
};
|
|
1862
|
+
let correctionAccess;
|
|
1863
|
+
const getCorrectionAccess = () => {
|
|
1864
|
+
if (!correctionAccess || correctionAccess.orchestrator !== state.orchestrator) {
|
|
1865
|
+
correctionAccess = {
|
|
1866
|
+
service: new EngramAccessService(state.orchestrator),
|
|
1867
|
+
orchestrator: state.orchestrator
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
return correctionAccess.service;
|
|
1871
|
+
};
|
|
1840
1872
|
return {
|
|
1841
1873
|
async store(sessionId, messages, control) {
|
|
1842
1874
|
throwIfBenchPhaseAborted(control, "store");
|
|
@@ -2381,6 +2413,71 @@ ${expanded.map((message) => `[${message.role}]: ${message.content}`).join("\n")}
|
|
|
2381
2413
|
});
|
|
2382
2414
|
sessionTurnCounters.clear();
|
|
2383
2415
|
},
|
|
2416
|
+
async correct(sessionId, text, _at, control) {
|
|
2417
|
+
throwIfBenchPhaseAborted(control, "correct");
|
|
2418
|
+
sessionId = normalizeBenchSessionId(sessionId);
|
|
2419
|
+
const access2 = getCorrectionAccess();
|
|
2420
|
+
const discardPlan = async (planId) => {
|
|
2421
|
+
await access2.correctionDiscard(planId, { sessionKey: sessionId }).catch(() => void 0);
|
|
2422
|
+
};
|
|
2423
|
+
let plan = await withBenchPhaseAbort(
|
|
2424
|
+
access2.correctionPlan({ text, sessionKey: sessionId }),
|
|
2425
|
+
control,
|
|
2426
|
+
"correct"
|
|
2427
|
+
);
|
|
2428
|
+
const sessionSource = benchCoreMemorySource(sessionId);
|
|
2429
|
+
const owned = new Set(
|
|
2430
|
+
(await readBenchCoreMemories(state.orchestrator)).filter((memory) => memory.frontmatter.source === sessionSource).map((memory) => memory.frontmatter.id)
|
|
2431
|
+
);
|
|
2432
|
+
let replanned = false;
|
|
2433
|
+
const decision = resolveSessionScopedCorrectionDecision(plan, owned, "initial");
|
|
2434
|
+
if (decision.kind === "no-owned-target") {
|
|
2435
|
+
await discardPlan(plan.planId);
|
|
2436
|
+
return { applied: false };
|
|
2437
|
+
}
|
|
2438
|
+
if (decision.kind === "replan") {
|
|
2439
|
+
await discardPlan(plan.planId);
|
|
2440
|
+
replanned = true;
|
|
2441
|
+
plan = await withBenchPhaseAbort(
|
|
2442
|
+
access2.correctionPlan({
|
|
2443
|
+
text,
|
|
2444
|
+
sessionKey: sessionId,
|
|
2445
|
+
targetIds: decision.targetIds
|
|
2446
|
+
}),
|
|
2447
|
+
control,
|
|
2448
|
+
"correct"
|
|
2449
|
+
);
|
|
2450
|
+
}
|
|
2451
|
+
const finalDecision = resolveSessionScopedCorrectionDecision(
|
|
2452
|
+
plan,
|
|
2453
|
+
owned,
|
|
2454
|
+
replanned ? "replanned" : "initial"
|
|
2455
|
+
);
|
|
2456
|
+
if (finalDecision.kind === "foreign-actions") {
|
|
2457
|
+
await discardPlan(plan.planId);
|
|
2458
|
+
throw new Error(
|
|
2459
|
+
`correction plan drafts actions against ${finalDecision.foreignIds.length} foreign-session memory(ies) (${finalDecision.foreignIds.join(", ")}) \u2014 the bench harness cannot scope this correction; refusing to apply or mismeasure`
|
|
2460
|
+
);
|
|
2461
|
+
}
|
|
2462
|
+
if (plan.actions.length === 0) {
|
|
2463
|
+
await discardPlan(plan.planId);
|
|
2464
|
+
if (replanned || plan.affected.length > 0) {
|
|
2465
|
+
throw new Error(
|
|
2466
|
+
`correction planner drafted no applicable action (${replanned ? "re-planned with explicit session-owned targets" : `${plan.affected.length} candidate(s) located`}; warnings: ${plan.warnings.join("; ") || "none"}) \u2014 refusing to measure the turn path as contract behavior`
|
|
2467
|
+
);
|
|
2468
|
+
}
|
|
2469
|
+
return { applied: false };
|
|
2470
|
+
}
|
|
2471
|
+
const outcome = await withBenchPhaseAbort(
|
|
2472
|
+
access2.correctionApply(plan.planId, {
|
|
2473
|
+
confirm: true,
|
|
2474
|
+
sessionKey: sessionId
|
|
2475
|
+
}),
|
|
2476
|
+
control,
|
|
2477
|
+
"correct"
|
|
2478
|
+
);
|
|
2479
|
+
return { applied: outcome.status === "applied" };
|
|
2480
|
+
},
|
|
2384
2481
|
async drain(control) {
|
|
2385
2482
|
throwIfBenchPhaseAborted(control, "drain");
|
|
2386
2483
|
const engine = getEngine();
|
|
@@ -3328,6 +3425,16 @@ function createTimeoutGuardedAdapter(adapter, options) {
|
|
|
3328
3425
|
drainTimeoutMs
|
|
3329
3426
|
);
|
|
3330
3427
|
}
|
|
3428
|
+
if (adapter.correct) {
|
|
3429
|
+
wrapped.correct = (sessionId, text, at, control) => phaseTimeoutMs === void 0 ? adapter.correct(sessionId, text, at, control) : run(`correct session=${sessionId}`, async (signal) => {
|
|
3430
|
+
const merged = mergeBenchPhaseControl(signal, control);
|
|
3431
|
+
try {
|
|
3432
|
+
return await adapter.correct(sessionId, text, at, merged.control);
|
|
3433
|
+
} finally {
|
|
3434
|
+
merged.cleanup();
|
|
3435
|
+
}
|
|
3436
|
+
});
|
|
3437
|
+
}
|
|
3331
3438
|
if (adapter.responder) {
|
|
3332
3439
|
wrapped.responder = phaseTimeoutMs === void 0 ? adapter.responder : wrapResponder(adapter.responder, run);
|
|
3333
3440
|
}
|
|
@@ -31955,6 +32062,142 @@ function computeMetricBundle(args) {
|
|
|
31955
32062
|
}
|
|
31956
32063
|
|
|
31957
32064
|
// src/benchmarks/remnic/memcorrect/adapters.ts
|
|
32065
|
+
var STOP_WORDS = /* @__PURE__ */ new Set([
|
|
32066
|
+
"the",
|
|
32067
|
+
"a",
|
|
32068
|
+
"an",
|
|
32069
|
+
"is",
|
|
32070
|
+
"are",
|
|
32071
|
+
"was",
|
|
32072
|
+
"were",
|
|
32073
|
+
"to",
|
|
32074
|
+
"of",
|
|
32075
|
+
"for",
|
|
32076
|
+
"and",
|
|
32077
|
+
"or",
|
|
32078
|
+
"but",
|
|
32079
|
+
"in",
|
|
32080
|
+
"on",
|
|
32081
|
+
"at",
|
|
32082
|
+
"by",
|
|
32083
|
+
"it",
|
|
32084
|
+
"my",
|
|
32085
|
+
"your",
|
|
32086
|
+
"we",
|
|
32087
|
+
"you",
|
|
32088
|
+
"i",
|
|
32089
|
+
"me",
|
|
32090
|
+
"this",
|
|
32091
|
+
"that",
|
|
32092
|
+
"with",
|
|
32093
|
+
"from",
|
|
32094
|
+
"not",
|
|
32095
|
+
"have",
|
|
32096
|
+
"has",
|
|
32097
|
+
"do",
|
|
32098
|
+
"does",
|
|
32099
|
+
"did",
|
|
32100
|
+
"be",
|
|
32101
|
+
"been",
|
|
32102
|
+
"being",
|
|
32103
|
+
"will",
|
|
32104
|
+
"would",
|
|
32105
|
+
"should",
|
|
32106
|
+
"could",
|
|
32107
|
+
"can",
|
|
32108
|
+
"may",
|
|
32109
|
+
"might",
|
|
32110
|
+
"must",
|
|
32111
|
+
"shall",
|
|
32112
|
+
"if",
|
|
32113
|
+
"then",
|
|
32114
|
+
"than",
|
|
32115
|
+
"so",
|
|
32116
|
+
"as",
|
|
32117
|
+
"go",
|
|
32118
|
+
"going",
|
|
32119
|
+
"forward",
|
|
32120
|
+
"instead",
|
|
32121
|
+
"last",
|
|
32122
|
+
"month",
|
|
32123
|
+
"now",
|
|
32124
|
+
"their",
|
|
32125
|
+
"them",
|
|
32126
|
+
"they",
|
|
32127
|
+
"he",
|
|
32128
|
+
"she",
|
|
32129
|
+
"his",
|
|
32130
|
+
"her",
|
|
32131
|
+
"got",
|
|
32132
|
+
"noting",
|
|
32133
|
+
"noted",
|
|
32134
|
+
"what",
|
|
32135
|
+
"setting",
|
|
32136
|
+
"preference",
|
|
32137
|
+
"update",
|
|
32138
|
+
"actually",
|
|
32139
|
+
"back",
|
|
32140
|
+
"went",
|
|
32141
|
+
"consider",
|
|
32142
|
+
"decided",
|
|
32143
|
+
"might",
|
|
32144
|
+
"someone",
|
|
32145
|
+
"asked",
|
|
32146
|
+
"mentioned",
|
|
32147
|
+
"said",
|
|
32148
|
+
"should",
|
|
32149
|
+
"change",
|
|
32150
|
+
"wrong",
|
|
32151
|
+
"saying",
|
|
32152
|
+
"record",
|
|
32153
|
+
"oh",
|
|
32154
|
+
"by",
|
|
32155
|
+
"way",
|
|
32156
|
+
"project"
|
|
32157
|
+
]);
|
|
32158
|
+
function tokenize4(text) {
|
|
32159
|
+
const matches = text.toLowerCase().match(/[a-z0-9][a-z0-9-]*/g);
|
|
32160
|
+
return (matches ?? []).filter((t) => !STOP_WORDS.has(t));
|
|
32161
|
+
}
|
|
32162
|
+
function termFrequencies(tokens) {
|
|
32163
|
+
const tf = /* @__PURE__ */ new Map();
|
|
32164
|
+
for (const token of tokens) {
|
|
32165
|
+
tf.set(token, (tf.get(token) ?? 0) + 1);
|
|
32166
|
+
}
|
|
32167
|
+
return tf;
|
|
32168
|
+
}
|
|
32169
|
+
var PromptOnlyBaselineAdapter = class {
|
|
32170
|
+
label = "prompt-only-baseline";
|
|
32171
|
+
turns = [];
|
|
32172
|
+
async reset() {
|
|
32173
|
+
this.turns = [];
|
|
32174
|
+
}
|
|
32175
|
+
async ingestTurn(sessionKey, role, text, at) {
|
|
32176
|
+
this.turns.push({ sessionKey, role, text, at });
|
|
32177
|
+
}
|
|
32178
|
+
async recall(query, sessionKey) {
|
|
32179
|
+
const queryTf = termFrequencies(tokenize4(query));
|
|
32180
|
+
if (queryTf.size === 0) return [];
|
|
32181
|
+
const scored = this.turns.filter((turn) => turn.sessionKey === sessionKey).map((turn) => {
|
|
32182
|
+
const turnTf = termFrequencies(tokenize4(turn.text));
|
|
32183
|
+
let overlap = 0;
|
|
32184
|
+
for (const [term, qCount] of queryTf) {
|
|
32185
|
+
const tCount = turnTf.get(term);
|
|
32186
|
+
if (tCount !== void 0) overlap += qCount * tCount;
|
|
32187
|
+
}
|
|
32188
|
+
return { turn, overlap };
|
|
32189
|
+
}).filter((entry) => entry.overlap > 0).sort((a, b) => {
|
|
32190
|
+
if (b.overlap !== a.overlap) return b.overlap - a.overlap;
|
|
32191
|
+
return this.turns.indexOf(b.turn) - this.turns.indexOf(a.turn);
|
|
32192
|
+
}).slice(0, 5).map((entry) => entry.turn.text);
|
|
32193
|
+
return scored;
|
|
32194
|
+
}
|
|
32195
|
+
async correct(text, sessionKey) {
|
|
32196
|
+
await this.ingestTurn(sessionKey, "user", text, (/* @__PURE__ */ new Date()).toISOString());
|
|
32197
|
+
}
|
|
32198
|
+
async runMaintenance() {
|
|
32199
|
+
}
|
|
32200
|
+
};
|
|
31958
32201
|
function createRemnicMemCorrectAdapter(adapter, options = {}) {
|
|
31959
32202
|
const label = options.label ?? "remnic-native";
|
|
31960
32203
|
const sessionPrefix = options.sessionPrefix ?? "memcorrect";
|
|
@@ -31975,7 +32218,12 @@ function createRemnicMemCorrectAdapter(adapter, options = {}) {
|
|
|
31975
32218
|
return trimmed.split(/\n\s*\n/).map((s) => s.trim()).filter((s) => s.length > 0);
|
|
31976
32219
|
},
|
|
31977
32220
|
async correct(text, sessionKey, at) {
|
|
31978
|
-
|
|
32221
|
+
const scopedSession = `${sessionPrefix}:${sessionKey}`;
|
|
32222
|
+
if (adapter.correct) {
|
|
32223
|
+
const outcome = await adapter.correct(scopedSession, text, at);
|
|
32224
|
+
if (outcome.applied) return;
|
|
32225
|
+
}
|
|
32226
|
+
await adapter.store(scopedSession, [
|
|
31979
32227
|
{ role: "user", content: text, timestamp: at }
|
|
31980
32228
|
]);
|
|
31981
32229
|
},
|
|
@@ -32023,7 +32271,17 @@ var FULL_OPTIONS2 = {
|
|
|
32023
32271
|
};
|
|
32024
32272
|
function resolveAdapter(options) {
|
|
32025
32273
|
const override = options.benchmarkOptions?.["adapter"];
|
|
32026
|
-
if (
|
|
32274
|
+
if (typeof override === "string") {
|
|
32275
|
+
if (override === "prompt-only") {
|
|
32276
|
+
const adapter = new PromptOnlyBaselineAdapter();
|
|
32277
|
+
return { adapter, adapterLabel: adapter.label };
|
|
32278
|
+
}
|
|
32279
|
+
if (override !== "remnic") {
|
|
32280
|
+
throw new Error(
|
|
32281
|
+
`memcorrect-v1 adapter must be one of ["remnic", "prompt-only"] (or an in-process MemCorrectSystemAdapter object); received "${override}"`
|
|
32282
|
+
);
|
|
32283
|
+
}
|
|
32284
|
+
} else if (override && typeof override === "object" && "reset" in override && "ingestTurn" in override && "recall" in override) {
|
|
32027
32285
|
const adapter = override;
|
|
32028
32286
|
return { adapter, adapterLabel: adapter.label ?? "custom" };
|
|
32029
32287
|
}
|
|
@@ -32980,7 +33238,7 @@ function assemblePack(task, condition, contract, injectSkills) {
|
|
|
32980
33238
|
};
|
|
32981
33239
|
}
|
|
32982
33240
|
function classifySkillTrigger(skill, task) {
|
|
32983
|
-
const taskTokens =
|
|
33241
|
+
const taskTokens = tokenize5(task.prompt + " " + task.subjectKeywords.join(" "));
|
|
32984
33242
|
const taskSet = new Set(taskTokens);
|
|
32985
33243
|
const appliesHits = skill.appliesWhen.filter((k) => taskSet.has(k));
|
|
32986
33244
|
const blocksHits = skill.doesNotApplyWhen.filter((k) => taskSet.has(k));
|
|
@@ -33001,7 +33259,7 @@ function classifySkillTrigger(skill, task) {
|
|
|
33001
33259
|
}
|
|
33002
33260
|
return { considered, injected: false, reason: "no trigger overlap" };
|
|
33003
33261
|
}
|
|
33004
|
-
function
|
|
33262
|
+
function tokenize5(text) {
|
|
33005
33263
|
return text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((t) => t.length > 0);
|
|
33006
33264
|
}
|
|
33007
33265
|
function rankCandidates(pack, task, sourceItems) {
|
|
@@ -36703,7 +36961,7 @@ var PROCEDURAL_REAL_SCENARIOS_SMOKE = [
|
|
|
36703
36961
|
];
|
|
36704
36962
|
|
|
36705
36963
|
// src/security/extraction-attack/tokenize.ts
|
|
36706
|
-
function
|
|
36964
|
+
function tokenize6(text) {
|
|
36707
36965
|
return text.toLowerCase().split(/[^a-z0-9]+/u).filter((t) => t.length > 2);
|
|
36708
36966
|
}
|
|
36709
36967
|
|
|
@@ -36745,7 +37003,7 @@ function createSeededRng2(seed) {
|
|
|
36745
37003
|
}
|
|
36746
37004
|
};
|
|
36747
37005
|
}
|
|
36748
|
-
var tokenizeContent =
|
|
37006
|
+
var tokenizeContent = tokenize6;
|
|
36749
37007
|
function recoveryTokensFor(memory) {
|
|
36750
37008
|
if (memory.tokens && memory.tokens.length > 0) {
|
|
36751
37009
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -37224,11 +37482,11 @@ function createSyntheticTarget(options) {
|
|
|
37224
37482
|
}
|
|
37225
37483
|
const normalized = memories.map((m) => ({
|
|
37226
37484
|
memory: m,
|
|
37227
|
-
tokens: new Set((m.tokens ??
|
|
37485
|
+
tokens: new Set((m.tokens ?? tokenize6(m.content)).map((t) => t.toLowerCase()))
|
|
37228
37486
|
}));
|
|
37229
37487
|
return {
|
|
37230
37488
|
async recall(query, recallOptions) {
|
|
37231
|
-
const qTokens =
|
|
37489
|
+
const qTokens = tokenize6(query);
|
|
37232
37490
|
if (qTokens.length === 0) return [];
|
|
37233
37491
|
const requestedNs = recallOptions?.namespace;
|
|
37234
37492
|
if (enforceNamespaceAcl && requestedNs !== void 0 && requestedNs !== allowedNamespace) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/bench",
|
|
3
|
-
"version": "9.6.
|
|
3
|
+
"version": "9.6.11",
|
|
4
4
|
"description": "Retrieval latency ladder benchmarks + CI regression gates for @remnic/core",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"hyparquet": "^1.25.7",
|
|
38
38
|
"yaml": "^2.4.2",
|
|
39
|
-
"@remnic/coding-graph": "^9.6.
|
|
40
|
-
"@remnic/core": "^9.6.
|
|
39
|
+
"@remnic/coding-graph": "^9.6.11",
|
|
40
|
+
"@remnic/core": "^9.6.11"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"tsup": "^8.5.1",
|